Search code examples
phparrayslaravelcollectionsmapping

Update first Laravel collection/array values based on related collection/array values or 0 if not found


I've been trying to get the difference between two collections:

$first = [
    "name" => "Test A",
    "scores" => [
        ["name" => "Values", "points" => 9],
        ["name" => "Algebra", "points" => 6],
        ["name" => "Science", "points" => 5],
        ["name" => "Total", "points" => 20]
    ]
];
$second = [
    "name" => "Test A",
    "scores" => [
        ["name" => "Values", "points" => 5],
        ["name" => "Algebra", "points" => 8],
        ["name" => "Total", "points" => 13]
    ]
];

My goal is to create a new collection with the missing key and value pairs based on the first collection, retain its values and the missing key will have a value of 0. The output that I want to achieve is:

[
    "name" => "Test A",
    "scores" => [
        ["name" => "Values", "points" => 5],
        ["name" => "Algebra", "points" => 8],
        ["name" => "Science", "points" => 0],
        ["name" => "Total", "points" => 13]
    ]
]

Using the diffKeys method:

$collection_new = $collection_1['scores']->diffKeys($collection_2['scores']);
dd($collection_new->all());

This will result to:

{
    "4": {
        "name": "Total",
        "points": 20
    },
}

Solution

  • The function down below should work, but the 1st array should contain all scores that the 2nd array has.

    $first['scores'] = mergeScores();
    
    function mergeScores()
    {
         return array_map(
             fn ($x) => array_merge($x, getPoint($x['name'])), 
             $first['scores']
         );
    }
    
    function getPoint($name)
    {
        $score = array_filter($second, fn ($x) => $x['name'] == $name);
        return ['point' => empty($score) ? 0 : $score['score']];
    }