В качестве примера у меня есть два массива: Многомерный массив 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);
}
}
$finalArray = [
0 => [ "price" => 155.95, "id" => 11, "quantity" => 1 ],
1 => [ "price" => 21, "id" => 13, "quantity" => 1 ]
];
Я немного застрял в том, как получить мой текущий выходной массив в желаемый массив.
Мне нужно сделать это, потому что мне нужно связать разные идентификаторы с двумя разными ценовыми категориями.
В моем случае цены отражают транзакции в порядке, поэтому line_items будут отображаться в том же порядке, что и цена, с которой они сравниваются. Переменная часть — это количество транзакций, являющихся частью этого заказа, и количество line_items в транзакции.
Привет, @micmackusa, большое спасибо за ваш метод решения этой проблемы, в моем случае цены отражают транзакции в порядке, поэтому line_items будет отображаться в том же порядке, что и цена, с которой они сравниваются. Переменная часть — это количество транзакций, являющихся частью этого заказа, и сколько line_items присутствует в транзакции.
Поэтому я считаю, что проблема заключается в вашем цикле 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);
Предлагаемое мной решение отличается от предоставленного вами кода тремя вещами:
array_search
вместо проверки $disposableTransactions_array[0]
, чтобы мы могли учесть несколько «сумм» в $price_array
$line_items
элементов, которые мы добавляем во время цикла foreach, в виде $sum_items
. Затем мы используем $sum_items
для создания нашего $output_array_entry
, который представляет собой все данные из $line_items
, которые мы использовали для нахождения суммы.$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.
Вы правы, я опечатался - я хотел сказать, что предоставленные массивы не были привязаны напрямую к переменным PHP - спасибо, что поправили меня @LelioFaieta
Привет, Райан, сейчас я работаю над твоим ответом, ты прав, он действительно работает! Просто хотел оставить этот комментарий, чтобы вы знали, что я прочитал ваш ответ
Хорошо, массив, с которым я работаю, построен из ответа API, поэтому я прогнал несколько примеров и рад сообщить, что структура выдерживает :). 1. Меня смущает (но это необходимо) то, что ключ $arrayKey помещается в массив для запуска через другой foreach(), но я думаю, это потому, что $lineitems_array является многомерным, поэтому потребуется 2 foreach()?
На самом деле вы можете изменить этот раздел, чтобы хранить только ту информацию, которая вам нужна — я просто сохранил всю запись $line_items, потому что это было проще всего. При этом, поскольку это многомерный массив, я считаю, что вам все равно понадобятся 2 цикла foreach(). Один для перебора необработанных данных в $line_items, а другой для перебора элементов, которые мы используем для поиска $sum
Хорошо, спасибо за объяснение и очень подробный ответ, мне нужно многому научиться ^^
Поскольку позиции ВСЕГДА идеально совпадают с порядком суммирования цен, следующий подход является подходящим/надежным.
Код: (Демо)
$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
Ах, но если я что-то упустил, если я поменяю порядок line_items, то они просто вставят последний элемент line_item в новый массив, а не вставят его в новый массив, если сумма цен соответствует элементам в price_array
Эти скрипты ОПРЕДЕЛЕННО не подходят для сценариев, где позиции и суммы не в порядке.
Хорошо, понял, я неправильно понял, это альтернативные ответы
Я думаю, что этот вопрос должен содержать более сложные случаи, чтобы лучше описать дополнительные возможности. Я имею в виду, это работает на ваших примерах данных, но всегда ли ваши реальные данные сконфигурированы/упорядочены таким образом, чтобы все идеально подходило? Пожалуйста, отредактируйте свой вопрос, чтобы удалить подпись Cheers, Boogabooga, и добавьте еще несколько тестовых случаев.