Суммируйте цены из массива, пока они не будут соответствовать определенному значению, которое определено в другом массиве.

В качестве примера у меня есть два массива: Многомерный массив 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
];

И я хочу добавить цены каждого массива из Array 1, пока они не сравняются с первым элементом Array 2.

В этот момент я хочу поместить массивы из Array 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 ]
   ]
];

До сих пор я пробовал это:

$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 ]
];

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

Мне нужно сделать это, потому что мне нужно связать разные идентификаторы с двумя разными ценовыми категориями.

В моем случае цены отражают транзакции в порядке, поэтому line_items будут отображаться в том же порядке, что и цена, с которой они сравниваются. Переменная часть — это количество транзакций, являющихся частью этого заказа, и количество line_items в транзакции.

Я думаю, что этот вопрос должен содержать более сложные случаи, чтобы лучше описать дополнительные возможности. Я имею в виду, это работает на ваших примерах данных, но всегда ли ваши реальные данные сконфигурированы/упорядочены таким образом, чтобы все идеально подходило? Пожалуйста, отредактируйте свой вопрос, чтобы удалить подпись Cheers, Boogabooga, и добавьте еще несколько тестовых случаев.

mickmackusa 14.02.2023 23:57

Привет, @micmackusa, большое спасибо за ваш метод решения этой проблемы, в моем случае цены отражают транзакции в порядке, поэтому line_items будет отображаться в том же порядке, что и цена, с которой они сравниваются. Переменная часть — это количество транзакций, являющихся частью этого заказа, и сколько line_items присутствует в транзакции.

BoogaBooga 15.02.2023 09:16
Laravel с Turbo JS
Laravel с Turbo JS
Turbo - это библиотека JavaScript для упрощения создания быстрых и высокоинтерактивных веб-приложений. Она работает с помощью техники под названием...
Аутсорсинг разработки PHP для индивидуальных веб-решений
Аутсорсинг разработки PHP для индивидуальных веб-решений
Услуги PHP-разработки могут быть экономически эффективным решением для компаний, которые ищут высококачественные услуги веб-разработки по доступным...
Еще один бенчмарк PHP
Еще один бенчмарк PHP
Сегодня я наткнулся на забавный пост на r/ProgrammerHumor, который заставил меня задуматься об одной вещи, которая меня всегда интересовала....
Преобразование данных с помощью красноречивых аксессоров и мутаторов в Laravel
Преобразование данных с помощью красноречивых аксессоров и мутаторов в Laravel
Laravel поставляется с мощной функцией под названием "Eloquent Accessors and Mutators".
Настройка PHP-проекта на MacOS: простое руководство для начинающих
Настройка PHP-проекта на MacOS: простое руководство для начинающих
PHP, широко используемый язык сценариев с открытым исходным кодом, необходим для веб-разработки. Его совместимость с MacOS делает его популярным...
Конечные и Readonly классы в PHP
Конечные и Readonly классы в PHP
В прошлом, когда вы не хотели, чтобы другие классы расширяли определенный класс, вы могли пометить его как final.
0
2
52
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Поэтому я считаю, что проблема заключается в вашем цикле foreach, в частности, в том, как вы определяете элементы, которые необходимо поместить в массив (вы проверяете только сумму в первом значении вашего массива цен по ключу $disposableTransactions_array[0]) .

Поскольку ваши массивы не были привязаны к переменным 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 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);

Предлагаемое мной решение отличается от предоставленного вами кода тремя вещами:

  1. Мы используем array_search вместо проверки $disposableTransactions_array[0], чтобы мы могли учесть несколько «сумм» в $price_array
  2. Мы отслеживаем ключ массива из $line_items элементов, которые мы добавляем во время цикла foreach, в виде $sum_items. Затем мы используем $sum_items для создания нашего $output_array_entry, который представляет собой все данные из $line_items, которые мы использовали для нахождения суммы.
  3. Сохраняем данные в $output_array

Однако я скажу, что это сильно зависит от того, как структурирован ваш массив $line_items. Если мы переместим любой из этих элементов в другой порядок, сложение может никогда не найти правильную сумму $sum внутри массива $price_array и ничего не вернет. Например, если наш $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. Это заставляет меня поверить, что вам может понадобиться еще одна проверка, но без дополнительного контекста я не уверен

Поскольку ваши массивы не были написаны на PHP, на самом деле это полностью допустимые массивы для php.

Lelio Faieta 14.02.2023 16:25

Вы правы, я опечатался - я хотел сказать, что предоставленные массивы не были привязаны напрямую к переменным PHP - спасибо, что поправили меня @LelioFaieta

Ryan 14.02.2023 16:30

Привет, Райан, сейчас я работаю над твоим ответом, ты прав, он действительно работает! Просто хотел оставить этот комментарий, чтобы вы знали, что я прочитал ваш ответ

BoogaBooga 14.02.2023 16:34

Хорошо, массив, с которым я работаю, построен из ответа API, поэтому я прогнал несколько примеров и рад сообщить, что структура выдерживает :). 1. Меня смущает (но это необходимо) то, что ключ $arrayKey помещается в массив для запуска через другой foreach(), но я думаю, это потому, что $lineitems_array является многомерным, поэтому потребуется 2 foreach()?

BoogaBooga 14.02.2023 16:56

На самом деле вы можете изменить этот раздел, чтобы хранить только ту информацию, которая вам нужна — я просто сохранил всю запись $line_items, потому что это было проще всего. При этом, поскольку это многомерный массив, я считаю, что вам все равно понадобятся 2 цикла foreach(). Один для перебора необработанных данных в $line_items, а другой для перебора элементов, которые мы используем для поиска $sum

Ryan 14.02.2023 17:00

Хорошо, спасибо за объяснение и очень подробный ответ, мне нужно многому научиться ^^

BoogaBooga 14.02.2023 17:08

Поскольку позиции ВСЕГДА идеально совпадают с порядком суммирования цен, следующий подход является подходящим/надежным.

Код: (Демо)

$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;
        },
        []
    )
);

Как видите, есть много-много способов решить эту задачу. Я даже не упоминал об использовании массива цен во время итерации... На этом я остановлюсь.

Привет, @mickmackusa, большое спасибо за ваш вклад :) Да, мой случай довольно прост, но может быть не для всех, где ваше решение отличное: D

BoogaBooga 15.02.2023 11:54

Ах, но если я что-то упустил, если я поменяю порядок line_items, то они просто вставят последний элемент line_item в новый массив, а не вставят его в новый массив, если сумма цен соответствует элементам в price_array

BoogaBooga 15.02.2023 12:04

Эти скрипты ОПРЕДЕЛЕННО не подходят для сценариев, где позиции и суммы не в порядке.

mickmackusa 15.02.2023 12:39

Хорошо, понял, я неправильно понял, это альтернативные ответы

BoogaBooga 15.02.2023 12:43

Другие вопросы по теме

Разобрать отформатированную строку с метками, написанными ЗАГЛАВНЫМИ БУКВАМИ, за которыми следует их значение, для создания ассоциативного массива.
Массив не расширяется при использовании в if
Создание таблицы из массива в React
Изменение вхождений значения в матрице
Почему адреса распределенного 2D-массива не такие, как я ожидаю?
Является ли мелкая копия массива дешевой, независимо от размера?
Сортировка слиянием в C возвращает список, содержащий дубликаты одних и тех же 3-4 чисел. Другие номера отсутствуют в отсортированном списке
Я застрял. Мне нужно настроить свои циклы, чтобы они продолжали сравнивать два моих массива, но не распечатывали все лишние символы.
Можно ли в C написать в одной строке вызов функции, которая имеет массив строк (т.е. ptr) или int, или... в качестве параметра?
Как обновить определенный элемент массива в TypeScript