Merge and group by several arrays

2019-03-02 08:35发布

问题:

I need to merge associative arrays and group by the name. Say I have such 3 arrays:

ARRAY1
    "/path/file.jpg"  =>  2, 
    "/path/file2.bmp" =>  1,
    "/file3.gif"      => 5,

ARRAY2
    "/path/file.jpg"  =>  1, 
    "/path/file2.bmp" =>  1,
    "/file3.gif"      => 0,

ARRAY3
    "/path/file.jpg"  =>  1, 
    "/path/file2.bmp" =>  1,

I need to merge these arrays to one and group them by filepath and have result of sum of their values. Something like:

SELECT filename, SUM(val) FROM files
GROUP BY filename

But with multiple input arrays. Arrays are short (around 20 elements max). Each array might have different size.

回答1:

one possible way

$rtn = array();
foreach ($array1 as $key=>$val)
{
  $rtn[$key]+=$val;
}

foreach ($array2 as $key=>$val)
{
  $rtn[$key]+=$val;
}

foreach ($array2 as $key=>$val)
{
  $rtn[$key]+=$val;
}

the above will assign the filename, SUM(val) as an associative array into $rtn



回答2:

[EDIT: I adapted the function (as suggested by John Green) to use func_get_args so you don't need to put all the seperate arrays in one array before you can use it.]

I think you could use the following function.

mergeArrays()
{
    $return = array();
    $arrays = func_get_args();
    foreach ($arrays as $array) {
        foreach ($array as $key => $val) {
            if (array_key_exists($key, $array) {
                $return[$key] += $val;
            } else {
                $return[$key] = $val;
            }
        }
    }
    return $return;
}


回答3:

You can use a RecursiveArrayIterator

$iterator = new RecursiveIteratorIterator(new RecursiveArrayIterator($paths));
foreach ($iterator as $path => $value) {
    $summed[$path] = isset($summed[$path]) ? $summed[$path] + $value : $value;
}
print_r($summed);

or array_walk_recursive and a Closure

$summed = array();
array_walk_recursive($paths, function($value, $path) use (&$summed) {
    $summed[$path] = isset($summed[$path]) ? $summed[$path] + $value : $value;
});

Both will give

Array
(
    [/path/file.jpg] => 4
    [/path/file2.bmp] => 3
    [/file3.gif] => 5
)