Слияние по значению массива (и выполнение расчетов с другими ключами)

Мне сложно найти жизнеспособное решение этой проблемы:

Это массив, который у меня есть, и я хочу сгруппировать этот массив с помощью product_name и подсчитать количество. Но структура массива должна оставаться неизменной.

 Array( [0] => Array ( [product_quantity] => 1 [product_name] => Appel ) [1] => Array ( [product_quantity] => 1 [product_name] => D-Day ) [2] => Array ( [product_quantity] => 4 [product_name] => D-Day ) [3] => Array ( [product_quantity] => 2 [product_name] => D-Day ) [4] => Array ( [product_quantity] => 1 [product_name] => Emiel ) [5] => Array ( [product_quantity] => 9 [product_name] => Emiel ) [6] => Array ( [product_quantity] => 3 [product_name] => Estella ) [7] => Array ( [product_quantity] => 4 [product_name] => Feeke ) [8] => Array ( [product_quantity] => 1 [product_name] => Feeke ) [9] => Array ( [product_quantity] => 7 [product_name] => Reset ) [10] => Array ( [product_quantity] => 1 [product_name] => Reset )) 

Что мне нужно для вывода:

 Array( [0] => Array ( [product_quantity] => 1 [product_name] => Appel ) [1] => Array ( [product_quantity] => 7 [product_name] => D-Day ) [2] => Array ( [product_quantity] => 10 [product_name] => Emiel ) [3] => Array ( [product_quantity] => 3 [product_name] => Estella ) [4] => Array ( [product_quantity] => 5 [product_name] => Feeke ) [5] => Array ( [product_quantity] => 8 [product_name] => Reset ) ) 

Я хотел бы услышать некоторые советы или решения о том, как справиться с этим!

    Цель может быть достигнута разными способами. Если вы стремитесь к скорости, используйте foreach для итерации по входному массиву, постепенно вычисляя и сохраняя значения в новый массив (тело функции обратного вызова ниже).

    Если вы array_reduce() произвести впечатление на своих товарищей по работе или рекрутера с вашими знаниями PHP, то используйте array_reduce() :

     $output = array_values( // We don't need the keys of the generated array array_reduce( // Incrementally process $input using a callback $input, // $carry is the partial result // $item is the currently processed item function(array $carry, array $item) { // Extract the product name into a local variable // we'll use it several times below $name = $item['product_name']; // If it's a new product then initialize its entry in the output if (! array_key_exists($name, $carry)) { $carry[$name] = array( 'product_quantity' => 0, 'product_name' => $name, ); } // Update the quantity of this group $carry[$name]['product_quantity'] += $item['product_quantity']; // Return the partial result return $carry; }, // Start with an empty array array() ) ); 

    Обновить

    ОП попросил в комментарии, как повторно использовать функцию обратного вызова и сделать ее настраиваемой ( «как я могу использовать параметр для создания 'product_name' динамически?» ).

    Вы можете поместить значение ( 'product_name' ) в переменную ( $key ) вне функции и use конструкцию языка use чтобы анонимная функция наследовала ее.

     $key = 'product_name'; // The values needs to be in a variable $output = array_values( array_reduce( $input, // The 'use' keyword lets the anonymous function use a copy of $key function(array $carry, array $item) use ($key) { $name = $item[$key]; // The rest of the callback's code comes here unchanged // ... // Return the partial result return $carry; }, array() ) ); 

    Дополнительную информацию см. В примере №3 о документации анонимных функций .

    Вы можете сохранить функцию обратного вызова в переменную. Это не улучшает ничего, кроме читаемости кода. Тем не менее, продолжайте читать, это всего лишь промежуточный шаг, реальная магия происходит ниже.

     $key = 'abc'; $f = function(array $carry, array $item) use ($key) { $name = $item[$key]; // The rest of the callback's code comes here unchanged // ... // Return the partial result return $carry; }; $output = array_values(array_reduce($input, $f, array())); 

    Чтобы сделать его действительно многократно используемым, вам нужно иметь способ генерировать обратные вызовы для разных значений $key . Давайте напишем простую функцию, которая создает параметризованные обратные вызовы:

     // This function creates a new callback that uses the value of argument $key function makeFn($key) { return function(array $carry, array $item) use ($key) { $name = $item[$key]; // The rest of the callback's code comes here unchanged // ... // Return the partial result return $carry; }; } 

    Теперь давайте использовать новую функцию. Он создает различные функции обратного вызова, которые можно использовать для уменьшения массива с помощью различных ключей:

     $output1 = array_values(array_reduce($input, makeFn('product_name'), array())); $output2 = array_values(array_reduce($input, makeFn('product_code'), array())); 

    Я не тестирую его, но думаю, что он может решить вашу проблему.

     $stocks = []; foreach ($products as $product) { if (isset($stocks[$product['product_name']])) { $stocks[$product['product_name']] += $product['product_quantity']; } else { $stocks[$product['product_name']] = $product['product_quantity']; } } $finalList = []; foreach ($stocks as $key => $stock) { $finalList[] = [ 'product_quantity' => $stock, 'product_name' => $key ]; } print_r($finalList);