简体   繁体   中英

How to compare and later merge two multidimensional arrays

I am trying to merge two multidimensional arrays in following way (example arrays are only examples, real ones are very long and have thousands of items):

$array_a:

[0] => Array
    (
        [date] => 2018-02-25 15:12
        [request] => 0
    )
[1] => Array
    (
        [date] => 2018-02-25 15:13
        [request] => 0
    )
[2] => Array
    (
        [date] => 2018-02-25 15:14
        [request] => 0
    )
[3] => Array
    (
        [date] => 2018-02-25 15:15
        [request] => 0
    )

$array_b:

[0] => Array
    (
        [date] => 2018-02-25 15:12
        [request] => 11
    )
[1] => Array
    (
        [date] => 2018-02-25 15:13
        [request] => 5
    )
[2] => Array
    (
        [date] => 2018-02-25 15:15
        [request] => 2
    )

Needed result:

[0] => Array
    (
        [date] => 2018-02-25 15:12
        [request] => 11
    )
[1] => Array
    (
        [date] => 2018-02-25 15:13
        [request] => 5
    )
[2] => Array
    (
        [date] => 2018-02-25 15:14
        [request] => 0
    )
[3] => Array
    (
        [date] => 2018-02-25 15:15
        [request] => 2
    )

Any? Thanks.

One way to go:

foreach($a as $v) {
        $res[$v['date']] = $v['request'];
}

foreach($b as $v) {
        if(isset($res[$v['date']])) {
                if($v['request'] > $res[$v['date']])
                        $res[$v['date']] = $v['request'];
        } else {
                $res[$v['date']] == $v['request'];
        }
}

foreach($res as $k=>$v)
        $out[] = array("date" => $k, "request" => $v);

where $a and $b are your arrays and $out is the final result.

How it works:

Since we are comparing the dates and we know they are unique, we put them into a temporary array(in my case $res ) as keys of the elements(keys of arrays are unique). For values of each element we compare the values of requests and store the bigger one.

So, the first foreach loop loops over the first array and adds elemenets to $res in the form of:

$res['2018-02-25 15:12'] = 0;

The second foreach loop loops over all elements of the second array, however, in here we also want to make sure we are using the bigger value for requests.

So this is, the if logic checks if the element exists, and if it does - gets the bigger value for requests and stores it to the date. If not - it does exactly what it did in the first foreach loop(creates new element).

Lastly, we want to put the array together to how it looked like, so we loop over $res and re-create the array as the original two looked like. The resulting $out holds what you requested.

I can give you the result, however I don't know the logic that goes in the callback body.

$array_c = array_values(array_reduce(array_merge($a, $b), function($carry, $item) {
    $carry[$item['date']] = $item;
    return $carry;
}, []));

https://3v4l.org/fSVoj

What I'm doing is combining the arrays (they're all subset'd, so no inherent conflicts), then I go through and "reduce down" to an array key > value pairing, the key being the date/time, the value being the set. This gives the effect of coalescing each date/time to the same key in that array. The callback in this case simply "remembers" the last date/time block encountered, hence the "not sure what's needed" question.

Lastly, I get a version of the array with the date/times replaced with indexes ( array_values() ). This is also interesting, because sorting by date would be fairly easy if the array_values() call were moved to later.

This gives:

array(4) {
  [0]=>
  array(2) {
    ["date"]=>
    string(16) "2018-02-25 15:12"
    ["request"]=>
    int(11)
  }
  [1]=>
  array(2) {
    ["date"]=>
    string(16) "2018-02-25 15:13"
    ["request"]=>
    int(5)
  }
  [2]=>
  array(2) {
    ["date"]=>
    string(16) "2018-02-25 15:14"
    ["request"]=>
    int(0)
  }
  [3]=>
  array(2) {
    ["date"]=>
    string(16) "2018-02-25 15:15"
    ["request"]=>
    int(2)
  }
}

Different things can be done, like only keep the first, or add each request (they're all zero in the first array). The mechanism should be the same though.

If you have to add values, you could use something like this :

$out = [];
// create new array using date as key, "object" as value.
foreach ($arr1 as $itm) {
    $out[$itm['date']] = $itm;
}
// foreach each element of the second array,
foreach ($arr2 as $itm) {
    // if it doesn't exists in the out array, simply add it
    if (!isset($out[$itm['date']])) $out[$itm['date']] = $itm ;
    // otherwise, add request to the first
    else $out[$itm['date']]['request'] += $itm['request'];
}
ksort($out); // Sort by date (Optional)
$out = array_values($out); // get values to remove dates from keys
print_r($out);

Outputs :

Array
(
    [0] => Array
        (
            [date] => 2018-02-25 15:12
            [request] => 11
        )

    [1] => Array
        (
            [date] => 2018-02-25 15:13
            [request] => 5
        )

    [2] => Array
        (
            [date] => 2018-02-25 15:14
            [request] => 0
        )

    [3] => Array
        (
            [date] => 2018-02-25 15:15
            [request] => 2
        )

)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM