Merging arrays based on a value of the key

生来就可爱ヽ(ⅴ<●) 提交于 2020-01-20 06:02:47

问题


I have two arrays of arrays that have an id key, and I'd like to merge the data together based on that array's key and key value. The data would look something like:

    $color = [
        ['id' => 1, 'color' => 'red'],
        ['id' => 2, 'color' => 'green'],
        ['id' => 3, 'color' => 'blue'],
    ];

    $size = [
        ['id' => 1, 'size' => 'SM'],
        ['id' => 2, 'size' => 'XL'],
        ['id' => 3, 'size' => 'MD'],
        ['id' => 4, 'size' => 'LG'],
    ];

    $combined = [
        ['id' => 1, 'color' => 'red', 'size' => 'SM'],
        ['id' => 2, 'color' => 'green', 'size' => 'XL'],
        ['id' => 3, 'color' => 'blue', 'size' => 'MD'],
        ['id' => 4, 'size' => 'LG'],
    ];

Is there a particularly efficient function or trick for handling something like this? Or should I just loop through the elements of one array and push the contents to the other?

I'm also using Laravel, and the data is a result of an eloquent query, so I can also utilize the collections if it would make the code cleaner.


回答1:


You can use array_replace_recursive to merge the arrays in your particular situation.

$color = array(
    array('id' => 1, 'color' => 'red'),
    array('id' => 2, 'color' => 'green'),
    array('id' => 3, 'color' => 'blue'),
);

$size = array(
    array('id' => 1, 'size' => 'SM'),
    array('id' => 2, 'size' => 'XL'),
    array('id' => 3, 'size' => 'MD'),
    array('id' => 4, 'size' => 'LG'),
);

$merged = array_replace_recursive($color, $size);

Output:

array(4) {
  [0]=>
  array(3) {
    ["id"]=>
    int(1)
    ["color"]=>
    string(3) "red"
    ["size"]=>
    string(2) "SM"
  }
  [1]=>
  array(3) {
    ["id"]=>
    int(2)
    ["color"]=>
    string(5) "green"
    ["size"]=>
    string(2) "XL"
  }
  [2]=>
  array(3) {
    ["id"]=>
    int(3)
    ["color"]=>
    string(4) "blue"
    ["size"]=>
    string(2) "MD"
  }
  [3]=>
  array(2) {
    ["id"]=>
    int(4)
    ["size"]=>
    string(2) "LG"
  }
}

Note: I used the traditional array layout because my PHP version won't support the new one yet :)

Second option

You can also use array_map. This will let you add as much arrays as you want with a little tweaking.

$merged = array_map(function ($c, $s) {
    return array_merge($c, $s);
}, $color, $size);

var_dump($merged); // See output above



回答2:


Use array_replace_recursive function for easy and fast way

array_replace_recursive($color, $size)



回答3:


Folllow this: array_replace_recursive() is recursive : it will recurse into arrays and apply the same process to the inner value.

$combined = array_replace_recursive($color, $size);

then you can print to see the result as bellow:

print_r($combined);



回答4:


Simple nested loop would solve the purpose.

foreach($size as $key => $value1) {
    foreach($color as $value2) {
        if($value1['id'] === $value2['id']){
            $size[$key]['title'] = $value2['color'];
        }               
    }
}
echo '<pre>';
print_r($size);

Output:

   Array
  (
   [0] => Array
    (
        [id] => 1
        [size] => SM
        [title] => red
    )

  [1] => Array
    (
        [id] => 2
        [size] => XL
        [title] => green
    )

[2] => Array
    (
        [id] => 3
        [size] => MD
        [title] => blue
    )

[3] => Array
    (
        [id] => 4
        [size] => LG
    )

)



回答5:


Try:

$out = array();
foreach ($size as $key => $value){
    if(!isset($color[$key])) { $color[$key] = array(); }  
    $out[] = array_merge((array)$value,(array)$color[$key]);
}

Output:

Array
(
    [0] => Array
        (
            [id] => 1
            [size] => SM
            [color] => red
        )

    [1] => Array
        (
            [id] => 2
            [size] => XL
            [color] => green
        )

    [2] => Array
        (
            [id] => 3
            [size] => MD
            [color] => blue
        )

    [3] => Array
        (
            [id] => 4
            [size] => LG
        )

)



回答6:


I'd suggest using laravel's collections, since this question has the laravel tag.

$color = collect(
    ['id' => 1, 'color' => 'red'],
    ['id' => 2, 'color' => 'green'],
    ['id' => 3, 'color' => 'blue']
);

$size = collect(
    ['id' => 1, 'size' => 'SM'],
    ['id' => 2, 'size' => 'XL'],
    ['id' => 3, 'size' => 'MD'],
    ['id' => 4, 'size' => 'LG']
);

$combined = $color->merge($size);



回答7:


Pure php solution is to use array_replace_recursive like this:

array_replace_recursive(
  array_combine(array_column($color, "id"), $color),
  array_combine(array_column($size, "id"), $size)
);

You should notice that array_replace_recursive merge arrays by keys. So, if you get such data from database:

$color = [
    ['id' => 1, 'color' => 'red'],
    ['id' => 2, 'color' => 'red']
];

$size = [
    ['id' => 2, 'size' => 'SM']
];

array_replace_recursive will return corrupted merge:

$combined = [
    ['id' => 2, 'color' => 'red', 'size' => 'SM'],
    ['id' => 2, 'color' => 'red']
];

The solution is to combine array_replace_recursive with array_column and array_combine for merging arrays by their's id field:

array_replace_recursive(
  array_combine(array_column($color, "id"), $color),
  array_combine(array_column($size, "id"), $size)
);

array_combine(array_column($color, "id"), $color) creates associative array with id as keys.

So, in your case it will return:

$combined = [
    1 => ['id' => 1, 'color' => 'red', 'size' => 'SM'],
    2 => ['id' => 2, 'color' => 'green', 'size' => 'XL'],
    3 => ['id' => 3, 'color' => 'blue', 'size' => 'MD'],
    4 => ['id' => 4, 'size' => 'LG'],
];



回答8:


Better way using loop. First calculate the max array the by count this number run a loop. It will work.




回答9:


array_replace_recursive() is one appropriate technique, but as you will plainly see from this demonstration, you must not rely on it unless the subarrays have matching id values at the exact same first level indexes. In other words, the function is not replacing based on corresponding id values, it is blindly replacing based on the array indexes. Notice how the resulting array data is mangled/ruined.

To fix this, you need to assign temporary associative keys using the id values. array_column() to the rescue. With a second parameter of null and a third parameter of 'id', new first level associative keys are assigned to each subarray without altering the subarrays themselves.

Code: (Demo)

$color = [
    ['id' => 1, 'color' => 'red'],
    ['id' => 2, 'color' => 'green'],
    ['id' => 3, 'color' => 'blue'],
];

$size = [
    ['id' => 3, 'size' => 'MD'],
    ['id' => 1, 'size' => 'SM'],
    ['id' => 4, 'size' => 'LG'],
    ['id' => 2, 'size' => 'XL'],
];

var_export(
    array_replace_recursive(
        array_column($color, null, 'id'),
        array_column($size, null, 'id')
    )
);

Output:

array (
  1 => 
  array (
    'id' => 1,
    'color' => 'red',
    'size' => 'SM',
  ),
  2 => 
  array (
    'id' => 2,
    'color' => 'green',
    'size' => 'XL',
  ),
  3 => 
  array (
    'id' => 3,
    'color' => 'blue',
    'size' => 'MD',
  ),
  4 => 
  array (
    'id' => 4,
    'size' => 'LG',
  ),
)

You will notice that the output is no longer indexed, but uses the id values as keys. If is imperative that the result array is indexed, re-index by calling array_values() on the result array.


Alternatively, if you insist on using nested loops, you should include a conditional break in your inner loop to prevent useless iterations, like this..

Code: (Demo)

foreach($color as $subarray1) {
    foreach ($size as $subarray2) {
        if($subarray1['id'] == $subarray2['id']) {
            $result[] = $subarray1 + $subarray2;
            break;
        }
    }
}


来源:https://stackoverflow.com/questions/38396616/merging-arrays-based-on-a-value-of-the-key

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!