foreach — значения массива суммы PHP по item.qty

Интересно, есть ли более быстрый способ суммировать, то есть вес каждого элемента по количеству?

$items = [
[
'qty'    => 1,
'weight' => 1,
],
[
'qty'    => 2,
'weight' => 1,
],
[
'qty'    => 3,
'weight' => 1,
],
];

$totalWeight = 0.0;
foreach ($items as $item) {
$totalWeight += $item['weight'] * $item['qty'];
}
echo $totalWeight . PHP_EOL;

Если мне не нужно смещение кол-во, я просто мог бы использовать

array_sum(array_column($items, 'weight'))

Но это не сработает в этом примере.

У кого-нибудь есть идея если а также как это может быть сделано быстрее?

Спасибо
/ cottton

РЕДАКТИРОВАТЬ

Тестовый скрипт:

$items = [];
for ($i = 0; $i < 1000; $i++) {
$items[] = [
'foo'    => 1,
'qty'    => $i,
'bar'    => 2,
'weight' => $i,
'baz'    => 3,
];
}
$totalWeight = 0.0;


$start = microtime(true);
for ($i = 0; $i < 10000; $i++) {
$totalWeight = 0.0;
foreach ($items as $item) {
$totalWeight += $item['weight'] * $item['qty'];
}
}
$elapsed = sprintf('%f', microtime(true) - $start);
echo "Elapsed: {$elapsed}\r\n";
echo "Total weight: {$totalWeight}\r\n";
// Elapsed: 0.744311
// Total weight: 332833500

2

Решение

использование https://www.w3schools.com/php/func_array_reduce.asp

    <?php
$items = [
[
'qty'    => 1,
'weight' => 1,
],
[
'qty'    => 2,
'weight' => 1,
],
[
'qty'    => 3,
'weight' => 1,
],
];


$totalWeight = array_reduce($items,
function($acc, $e) { return $acc + ($e['weight'] * $e['qty']); });
echo $totalWeight . PHP_EOL;

?>
2

Другие решения

Вы можете карта array_product по внутренним массивам и array_sum результирующий массив продуктов.

$totalWeight = array_sum(array_map('array_product', $items));

(Это может не сработать, если показанный вами пример был упрощен для данного вопроса, а внутренние массивы содержат другие поля, которые не показаны.)

2

Вот метод, который зацикливает уникальные веса и находит сумму qty каждого веса и умножает ее на вес.

В вашем случае это делает один цикл.

$weights = array_column($items, 'weight');
$result =0;
Foreach(array_unique($weights) as $weight){
// Finds the items with the weight 1 for example
$weightitems = preg_grep("/". $weight . "/", $weights);
// Sum quantity of items with the weight of 1 and multiply with weight (1).
$result += array_sum(array_column(array_intersect_key($items, $weightitems), "qty")) * $weight;
}
Echo $result;

Обратите внимание, что я добавил «5» только для того, чтобы убедиться, что он работает правильно в моем примере кода.

https://3v4l.org/V293P


Чуть более оптимизированный код, но, насколько я вижу, он не быстрее простого цикла.
Я могу сделать это в 4 раза медленнее, в зависимости от ввода, но не могу подобрать его ближе, чем это.

$weights =array_unique(array_column($items, 'weight'));
$result =[];
Foreach($weights as $weight){
$weightitems = array_filter($items, function ($var) use ($weight) {
return ($var['weight'] == $weight);
});
$result[] = array_sum(array_column($weightitems, "qty")) * $weight;
}
Echo array_sum($result) ."\n";

https://3v4l.org/aB7d9



Насколько точно это должно быть?

Это быстрее, чем зацикливание, но отключено на 1 на 3000 элементов и всего 17992.
Это в пределах погрешности, то это быстрее.

Я вычисляю среднее значение sumproduct двух столбцов, используя array_sum, array_column и count.

$count = count($items);
$weights = array_sum(array_column($items, 'weight'));
$qty = array_sum(array_column($items, 'qty'));

Echo ($qty * $weights)/$count ."\n";
// 17991 (should be 17992)

https://3v4l.org/c3CIg

Я думаю, что попробовал все возможные решения сейчас.

0