skip to Main Content

As an example I have two arrays:
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.

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

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’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.

2

Answers


  1. 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 => ['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 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 => $item){
        //add the price of the current items to the sum
        $sum += (float)$item['price'];
        //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 => ['price' => 155.95, 'id' => 11, 'quantity' => 1],
        1 => ['price' => 21, 'id' => 13, 'quantity' => 1],
        2 => ['price' => 41.99, 'id' => 12, 'quantity' => 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

    Login or Signup to reply.
  2. 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['price'];
        if ($bucket_sum >= $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], 'price')) == $price_array[$lastKey]
        
        ) {
            unset($ref);
            $result[] = &$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] ?? [], 'price')) == $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.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search