Мне сложно найти жизнеспособное решение этой проблемы:
Это массив, который у меня есть, и я хочу сгруппировать этот массив с помощью 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);