Sum the prices from an array until they correspond with a specific value, that is defined in a different array

huangapple go评论64阅读模式
英文:

Sum the prices from an array until they correspond with a specific value, that is defined in a different array

问题

以下是您要翻译的部分:

作为示例,我有两个数组: 
多维数组1:

$line_items = [
0 => ['price' => 41.99, 'id' => 12, 'quantity' => 1],
1 => ['price' => 155.95, 'id' => 11, 'quantity' => 1],
2 => ['price' => 21, 'id' => 13, 'quantity' => 1]
];


常规数组2:

$price_array = [
0 => 197.94,
1 => 21.00
];


我想要将数组1中的每个数组的价格相加,直到它们等于数组2的第一个元素。

在那一点上,我想将用于总结该价格的数组从数组1中推送到一个新数组中,然后重复这个过程。

因此,例如,从上面的数组中,新数组将如下所示:

$finalArray = [
[
0 => [ "price" => 41.99, "id" => 12, "quantity" => 1 ],
1 => [ "price" => 155.95, "id" => 11, "quantity" => 1 ]
],[
0 => [ "price" => 21, "id" => 13, "quantity" => 1 ]
]
];


到目前为止,我已经尝试了这个:
```php
$disposableTransactions_array = [];

foreach($lineitems_array as $lineitems){
    //将价格添加到总和中
    $sum += $lineitems['price'];
    //如果$sum达到数组中的第一个元素的值
    if($sum == $disposableTransactions_array[0]){
        //将$lineitems推送到新数组中
        $finalPrices_array[] = $lineitems;
        //重置总和
        $sum = 0;
        /* 从已检查的数组中删除第一个元素,以允许检查数组中的下一个元素 */
        array_shift($disposableTransactions_array);
    }
}

然而,我只获得了这个输出,而不是将两个一起总结的数组推送到多维数组中:

$finalArray = [
    0 => [ "price" => 155.95, "id" => 11, "quantity" => 1  ],
    1 => [ "price" => 21, "id" => 13, "quantity" => 1 ]
];

我有点困惑如何将我当前的输出数组转换为我所期望的数组。

我需要这样做是因为我需要将不同的id关联到两个不同的价格点。

在我的情况下,价格反映了订单中的交易,因此line_items将按照它们与要进行比较的价格出现的顺序排列。可变部分是这个订单中有多少交易和一个交易中有多少line_items。


<details>
<summary>英文:</summary>

As an example I have two arrays: &lt;br&gt;
Multidimensional Array 1:

$line_items = [
0 => ['price' => 41.99, 'id' => 12, 'quantity' => 1],
1 => ['price' => 155.95, 'id' => 11, 'quantity' => 1],
2 => ['price' => 21, 'id' => 13, 'quantity' => 1]
];


Regular Array 2: 

$price_array = [
0 => 197.94,
1 => 21.00
];

And I want to add the prices of each array from `Array 1` until they equal to the first element of `Array 2`.

At that point, I want to push the arrays from `Array 1` that were used to sum that price into a new array, and repeat the process. &lt;br&gt;

So for example the new array would look like this from the above arrays: 

$finalArray = [
[
0 => [ "price" => 41.99, "id" => 12, "quantity" => 1 ],
1 => [ "price" => 155.95, "id" => 11, "quantity" => 1 ]
],[
0 => [ "price" => 21, "id" => 13, "quantity" => 1 ]
]
];

so far I have tried this:

$disposableTransactions_array = [];

foreach($lineitems_array as $lineitems){
//add the prices to the sum
$sum += $lineitems['price'];
//should the $sum reach the value of the first element in array
if($sum == $disposableTransactions_array[0]){
//push the $lineitems into a new array
$finalPrices_array[] = $lineitems;
//reset the sum
$sum = 0;
/* remove first element from checked array to allow the next element in array to be checked */
array_shift($disposableTransactions_array);
}
}

&lt;br&gt;
However, I am only getting this as output, rather than both arrays that were summed together being pushed into a multidimensional array: 

$finalArray = [
0 => [ "price" => 155.95, "id" => 11, "quantity" => 1 ],
1 => [ "price" => 21, "id" => 13, "quantity" => 1 ]
];

I am a bit stuck on how to get my currently ouput array, into the array I desire.

I need to do this because I need to associate the different id&#39;s to the two different price points.

In my case the prices reflect transactions in an order, so line_items will appear in the same order as the price they are being compared against. The variable part is how many transactions are part of this order and how many line_items are present in a transaction.

</details>


# 答案1
**得分**: 1

以下是翻译好的部分:

"我相信问题出在你的foreach循环中,具体来说,是你识别需要放入数组的项目的方式(你只检查了价格数组中键`$disposableTransactions_array[0]`的第一个值的总和)。

由于你的数组没有附加到PHP变量*,我在命名约定上进行了一些改动,但这段代码产生了你所期望的输出:

```php
$line_items = [
    0 => ['price' => 41.99, 'id' => 12, 'quantity' => 1],
    1 => ['price' => 155.95, 'id' => 11, 'quantity' => 1],
    2 => ['price' => 21, 'id' => 13, 'quantity' => 1]
];
$price_array = [
    0 => 197.94,
    1 => 21.00
];
//$output_array存储我们的输出
$output_array = [];
//$sum用于我们的数学运算,设置一个默认值
$sum = 0;
//$sum_items是用于构建$output_array的项目
$sum_items = [];
//遍历每个$line_items
foreach($line_items as $arrayKey => $item){
    //将当前项目的价格添加到总和中
    $sum += (float)$item['price'];
    //将当前$line_items数组键添加到$sum_items中
    $sum_items[] = $arrayKey;
    //检查当前$sum是否在$price_array中
    $key = array_search((float)$sum, $price_array);
    if(false !== $key){
        //我们找到了总和,清空$output_array_entry,以便我们有一个干净的起点
        $output_array_entry = [];
        //遍历我们用来获取当前$sum的每个项目
        foreach($sum_items as $item_id){
            //将每个项目完全添加到$output_array_entry中,来自$line_items
            $output_array_entry[] = $line_items[$item_id];
        }
        //将我们刚刚构建的$output_array_entry添加到$output_array中
        $output_array[] = $output_array_entry;
        //重置我们的变量
        $sum_items = [];
        $sum = 0;
    }
}
var_dump($output_array);

我建议的解决方案与你提供的代码有三个不同之处:

  1. 我们使用array_search而不是检查$disposableTransactions_array[0],这样可以考虑$price_array中的多个“总和”。
  2. 我们跟踪了在foreach循环中添加在$line_items中的项目的数组键,形式为$sum_items。然后,我们使用$sum_items来创建$output_array_entry,其中包含了我们用于找到总和的$line_items中的所有数据。
  3. 我们将数据保存到$output_array中。

不过,我必须指出,这在很大程度上依赖于你的$line_items数组的结构。如果我们将这些项目移动到不同的顺序,加法可能永远无法在$price_array中找到正确的$sum,并且将返回空值。例如,如果我们的$line_items如下所示:

$line_items = [
    0 => ['price' => 155.95, 'id' => 11, 'quantity' => 1],
    1 => ['price' => 21, 'id' => 13, 'quantity' => 1],
    2 => ['price' => 41.99, 'id' => 12, 'quantity' => 1],
];

第一次循环时,我们的$sum为155.95,然后在下一次循环中,$sum为176.95,然后在第三次循环中,$sum为218.94 - 都不在我们的$price_array中。这使我相信你可能需要进行另一个检查,但没有更多的上下文,我不确定。"

英文:

So I believe the problem is within your foreach loop, specifically with the way you're identifying the items that need to be put into the array (you're only checking for the sum on the first value of your prices array at key $disposableTransactions_array[0]).

Since your arrays weren't attached to PHP variables*, I took some liberties in naming conventions but this code produces the output you're looking for:

$line_items = [
	0 =&gt; [&#39;price&#39; =&gt; 41.99, &#39;id&#39; =&gt; 12, &#39;quantity&#39; =&gt; 1],
	1 =&gt; [&#39;price&#39; =&gt; 155.95, &#39;id&#39; =&gt; 11, &#39;quantity&#39; =&gt; 1],
	2 =&gt; [&#39;price&#39; =&gt; 21, &#39;id&#39; =&gt; 13, &#39;quantity&#39; =&gt; 1]
];
$price_array = [
	0 =&gt; 197.94,
	1 =&gt; 21.00
];
//$output_array stores our output
$output_array = [];
//$sum is used for our math, set a default value
$sum = 0;
//$sum_items are the items used to build the $output_array
$sum_items = [];
//loop through each $line_items
foreach($line_items as $arrayKey =&gt; $item){
    //add the price of the current items to the sum
	$sum += (float)$item[&#39;price&#39;];
    //add the current $line_items array key to $sum_items
	$sum_items[] = $arrayKey;
    //check to see if our current $sum is in $price_array
	$key = array_search((float)$sum, $price_array);
	if(false !== $key){
		//we found the sum, clear out the $output_array_entry so we have a clean slate
		$output_array_entry = [];
        //loop through each item we used to get our current $sum
		foreach($sum_items as $item_id){
            //add each item in its entirety to the $output_array_entry from $line_items
			$output_array_entry[] = $line_items[$item_id];
		}
        //add the $output_array_entry we just built to $output_array
		$output_array[] = $output_array_entry;
        //reset our variables
		$sum_items = []; 
		$sum = 0;
	}
}
var_dump($output_array);

The solution I'm proposing does three things different from the code you provided:

  1. We use array_search instead of checking on $disposableTransactions_array[0] so we can account for multiple "sums" in the $price_array
  2. We keep track of the array key from $line_items of the items we're adding together during the foreach loop in the form of $sum_items. We then use $sum_items to create our $output_array_entry which is all of the data from $line_items that we used to find the sum.
  3. We save the data to $output_array

I will say though, this relies heavily on the way your $line_items array is structured. If we move any of those items to a different order, the addition may never find the correct $sum inside of $price_array and will return nothing. For Example, if our $line_items looks like this:

$line_items = [
    0 =&gt; [&#39;price&#39; =&gt; 155.95, &#39;id&#39; =&gt; 11, &#39;quantity&#39; =&gt; 1],
    1 =&gt; [&#39;price&#39; =&gt; 21, &#39;id&#39; =&gt; 13, &#39;quantity&#39; =&gt; 1],
    2 =&gt; [&#39;price&#39; =&gt; 41.99, &#39;id&#39; =&gt; 12, &#39;quantity&#39; =&gt; 1],
];

The first time we loop through our $sum is 155.95, then on the next pass our $sum is 176.95, and then on the third pass $sum is 218.94 - none of which are in our $price_array. This makes me believe you may need another check - but without more context I'm not sure

答案2

得分: 1

因为每个行项目始终与总价格的顺序完美对齐,以下方法是合适/可靠的。

$bucket_sum = 0;
$bucket_index = 0;
$result = [];
foreach ($line_items as $row) {
    $result[$bucket_index][] = $row;
    $bucket_sum += $row['price'];
    if ($bucket_sum >= $price_array[$bucket_index]) {
        $bucket_sum = 0;
        ++$bucket_index;
    }
}
var_export($result);

将行项目持续添加到结果数组中的当前元素,直到其价格总和达到价格数组中定义的总和。然后增加索引并重置总和变量,继续按照前述方法添加行项目。


作为个人挑战,我想尝试使用引用变量编写一个解决方案。

$result = [];
foreach ($line_items as $row) {
    $lastKey = array_key_last($result);
    if (
        !$result
        || array_sum(array_column($result[$lastKey], 'price')) == $price_array[$lastKey]
    ) {
        unset($ref);
        $result[] = &$ref;
    }
    $ref[] = $row;
}
var_export($result);

最后,一种紧凑的、函数式的方法:

var_export(
    array_reduce(
        $line_items,
        function($result, $row) use ($price_array) {
            $index = (int) array_key_last($result);
            $index += array_sum(array_column($result[$index] ?? [], 'price')) == $price_array[$index];
            $result[$index][] = $row;
            return $result;
        },
        []
    )
);

正如你所看到的,有很多方法来解决这个任务。我甚至没有提到在迭代过程中消耗价格数组...我就到这里。

英文:

Because the line items ALWAYS perfectly align with the order of the summed prices, the following approach is suitable/reliable.

Code: (Demo)

$bucket_sum = 0;
$bucket_index = 0;
$result = [];
foreach ($line_items as $row) {
    $result[$bucket_index][] = $row;
    $bucket_sum += $row[&#39;price&#39;];
    if ($bucket_sum &gt;= $price_array[$bucket_index]) {
        $bucket_sum = 0;
        ++$bucket_index;
    }
}
var_export($result);

Keep pushing line items into the current element in the result array until its price total reach the defined sum in the price array. Then increment the index and reset the sum variable and proceed with pushing line items as described in the previous sentence.


As a personal challenge, I wanted to try to script a solution using reference variables. Demo

$result = [];
foreach ($line_items as $row) {
    $lastKey = array_key_last($result);
    if (
        !$result
        || array_sum(array_column($result[$lastKey], &#39;price&#39;)) == $price_array[$lastKey]
    
    ) {
        unset($ref);
        $result[] = &amp;$ref;
    }
    $ref[] = $row;
}
var_export($result);

And finally, a dense, functional-style approach: Demo

var_export(
    array_reduce(
        $line_items,
        function($result, $row) use ($price_array) {
            $index = (int) array_key_last($result);
            $index += array_sum(array_column($result[$index] ?? [], &#39;price&#39;)) == $price_array[$index];
            $result[$index][] = $row;
            return $result;
        },
        []
    )
);

As you can see, there are many, many ways to attack this task. I didn't even mention consuming the price array while iterating ...I'll stop here.

huangapple
  • 本文由 发表于 2023年2月14日 22:33:32
  • 转载请务必保留本文链接:https://go.coder-hub.com/75449322.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定