如何使用foreach迭代两个相同长度的集合

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
    }
  ]
}

First of all, requirements

A solution with using the foreach-loop to traverse through the collection(s) is wanted

Approach with two collections with same items in same order

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;
}

Approach regardless of sorting and item count

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;
}

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'];
}

Demo

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.

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

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 :)