Reputation: 67525
If we want to concat some properties of two collections assuming they have the same length, e.g :
Collection 1 :
$collection1 = Collection { ▼
#items: array:2 [ ▼
0 => Item { ▼
+id: 1
+first_name: 'first_name 1'
+last_name: 'first_name 1'
+nbr_hours: 9
}
1 => Item { ▼
+id: 2
+first_name: 'first_name 2'
+last_name: 'first_name 2'
+nbr_hours: 10
}
]
}
Collection 2 :
$collection2 = Collection { ▼
#items: array:2 [ ▼
0 => Item { ▼
+id: 1
+first_name: 'first_name 1'
+last_name: 'first_name 1'
+nbr_hours: 10
}
1 => Item { ▼
+id: 2
+first_name: 'first_name 2'
+last_name: 'first_name 2'
+nbr_hours: 12
}
]
}
How we could loop through them in same time and concat the nbr_hours
attributes, for example so the output will be like :
$nested_collection = Collection { ▼
#items: array:2 [ ▼
0 => Item { ▼
+id: 1
+first_name: 'first_name 1'
+last_name: 'first_name 1'
+nbr_hours: 19
}
1 => Item { ▼
+id: 2
+first_name: 'first_name 2'
+last_name: 'first_name 2'
+nbr_hours: 22
}
]
}
Upvotes: 3
Views: 2371
Reputation: 7289
A solution with using the foreach-loop to traverse through the collection(s) is wanted
You can use the index of each element that you traverse to get the "partner element" from the other collection, in case the item count and sorting is the same for each collection.
foreach($collection1 as $index => $item){
$hours = $item->nbr_hours . $collection2[$index]->nbr_hours;
}
When your collection elements are not in the same order, or the collection item count is different, the query looks a bit more complex. In this case, you need to query elements where the id's are the same. To achieve that, we can change the collection indexes to the id's of the containing model. Now we can again use the index of one element to find the corresponding one in the other collection.
$collection2 = $collection2->keyBy('id'); //Change indexes to model ids
$collection1 = $collection1->keyBy('id'); //For both collections
foreach($collection1 as $index => $item){
$hours = $item->nbr_hours . $collection2->get($index)->nbr_hours;
}
Upvotes: 1
Reputation: 3572
A small modification to @AmitGupta's answer. If the collection 2 is required to be matched by $item->id
. Try the below answer. :)
$nested_collection = $collection1->map(function($item) use ($collection2) {
$item->nbr_hours += $collection2->where('id', $item->id)->first()->nbr_hours;
return $item;
});
Let me know :)
Upvotes: 1
Reputation: 17678
You can use map
method as:
$nested_collection = $collection1->map(function ($item, $key) use($collection2) {
$item->nbr_hours = $item->nbr_hours + $collection2->get($key)->nbr_hours;
return $item;
});
Note - If the values are not on same order then you can use values
method.
The values method returns a new collection with the keys reset to consecutive integers
Upvotes: 1
Reputation: 7083
If you want to use Collection methods, you could use this approach:
$zip = $c1->zip($c2->toArray());
$m = $zip->map(function($items, $key) {
$sum = 0;
foreach ($items as $k => $item) {
$sum += $item['nbr_hours'];
}
$r = $items[$k];
$r['nbr_hours'] = $sum;
return $r;
});
Basically, zip
method will "merge" the arrays in the same key. Then, if you use the map
method, you can iterate over the main keys. After that, you can deal with both arrays as items. So, you can make any kind of operations you need, and then return a new array as the result.
Upvotes: 1
Reputation: 31749
This is a example with array what you can do to achieve this -
$c1 = [
['id' => 1, 'hrs' => 9],
['id' => 2, 'hrs' => 12],
];
$c2 = [
['id' => 1, 'hrs' => 10],
['id' => 2, 'hrs' => 11],
];
foreach($c1 as &$c) {
// get the index for the id from the 2nd array
$c2_index = array_search($c['id'], array_column($c2, 'id'));
// Increment the value
$c['hrs'] += $c2[$c2_index]['hrs'];
}
Upvotes: 0