Reputation: 508
I have a Laravel Collection with a lot of duplicated items like that:
[
id: 'NAME1',
prop1: 'yes',
prop2: null,
prop3: 'bla',
prop4: null
],
[
id: 'NAME1',
prop1: null,
prop2: 'yes'
prop3: null,
prop4: 'bla'
]
And i want to merge the elements with the same 'id' property, and get a collection like that, preserving both properties:
[
id: 'NAME1',
prop1: 'yes',
prop2: 'yes',
prop3: 'bla',
prop4: 'bla'
]
When i use $collection->unique('id')
i only get a collection like that, losing the prop2 and prop4 of
the second element:
[
id: 'NAME1',
prop1: 'yes',
prop2: null,
prop3: 'bla',
prop4: null
]
How can i solve it? I doesn't find any method of Laravel Collections which could merge elements of a Collection when one of the elements had a null key.
Upvotes: 1
Views: 1869
Reputation: 606
Here's a macro that will do what you want:
use Illuminate\Support\Collection;
Collection::macro('mergeByKey', function ($key) {
return $this->groupBy($key)->map(function($group) {
$filteredGroup = collect($group)->map(function($item) {
return collect($item)->reject(function($value, $key) {
return $value === null;
});
});
return array_merge(...$filteredGroup->toArray());
})->values();
});
Then you can use it on a collection like this:
$collection = collect([
[
'id' => 'NAME1',
'prop1' => 'yes',
'prop2' => null,
'prop3' => 'bla',
'prop4' => null
],
[
'id' => 'NAME1',
'prop1' => null,
'prop2' => 'yes',
'prop3' => null,
'prop4' => 'bla'
],
[
'id' => 'NAME2',
'prop1' => null,
'prop2' => 'fdsa',
'prop3' => null,
'prop4' => 'asdf'
],
[
'id' => 'NAME2',
'prop1' => 'fdsa',
'prop2' => null,
'prop3' => 'asdf',
'prop4' => null
],
]);
$result = $collection->mergeByKey('id');
Result:
Collection {#268 ▼
#items: array:2 [▼
0 => array:5 [▼
"id" => "NAME1"
"prop1" => "yes"
"prop3" => "bla"
"prop2" => "yes"
"prop4" => "bla"
]
1 => array:5 [▼
"id" => "NAME2"
"prop2" => "fdsa"
"prop4" => "asdf"
"prop1" => "fdsa"
"prop3" => "asdf"
]
]
}
Upvotes: 1
Reputation: 101
So you want to merge all non-null properties for each id (you have only one ID in your list, but I assume there can be many) 1) group by id and get the list of [id => [all property lists for id]] 2) for each id: 2a) remove empty properties from each list 2b) merge all lists into one
It can be done this way with laravel collections:
$data = '[
{
"id": "NAME1",
"prop1": "yes",
"prop2": null,
"prop3": "bla",
"prop4": null
},
{
"id": "NAME1",
"prop1": null,
"prop2": "yes",
"prop3": null,
"prop4": "bla"
},
{
"id": "NAME2",
"prop1": "no",
"prop2": "dah",
"prop4": "bla"
}
]
';
$coll = collect(json_decode($data, JSON_OBJECT_AS_ARRAY))
->groupBy('id')
->map(function ($propGroup) {
//for each group of 'objects' of property lists
return $propGroup
->map(function ($props) {
//remove empty properties
return collect($props)->filter(function ($prop) {
return !empty($prop);
});
})
->reduce(function ($carry, $item) {
return $carry->merge($item);
}, collect());
});
Upvotes: 0