Как объединить ассоциативных массива по значению полей?

Ссылка скопирована
PHP
1 ответ

есть два массива, у которых есть поле "date" и есть показатели, например, price и quantity

как объединить эти массивы по полю date так чтобы показатели price и quantity при этом сложились?

$dates1[] = [     [         'date' => "01.08.2023",         'qty' => 100     ],     [         'date' => "02.08.2023",         'qty' => 15,     ], ];  $dates1[] = [     [         'date' => "01.08.2023",         'qty' => 0     ],     [         'date' => "03.08.2023",         'qty' => 25,     ], ];   $result = [     [         'date' => "01.08.2023",         'qty' => 100     ],     [         'date' => "02.08.2023",         'qty' => 15,     ],     [         'date' => "03.08.2023",         'qty' => 25,     ], ];

$dates1[] = [ [ 'date' => "01.08.2023", 'qty' => 100 ], [ 'date' => "02.08.2023", 'qty' => 15, ], ]; $dates1[] = [ [ 'date' => "01.08.2023", 'qty' => 0 ], [ 'date' => "03.08.2023", 'qty' => 25, ], ]; $result = [ [ 'date' => "01.08.2023", 'qty' => 100 ], [ 'date' => "02.08.2023", 'qty' => 15, ], [ 'date' => "03.08.2023", 'qty' => 25, ], ];

Дополнительно:

Пройти оба циклом, создавая новый массив, где date - ключ, а значения - price и quality, суммирующиеся, если они уже есть. Особенно актуально, если date не уникален.
Впрочем, вопрос безобразно неконкретен и может предполагать кучу разных вариантов того, что реально нужно ТС.

  • Ну вы бы хотя бы примеры массивов кинули
  • Adamos, ну через циклы то каждый может. Но это джуновский подход. Профи используют функции высшего порядка с колбеками или функции для работы с массивами.
  • Слава, джуна от сеньора отличает не это. мне кажется мы уже беседовали с вами на эту тему.
  • Дмитрий,
    $dates1[] = [     [         'date' => "01.08.2023",         'qty' => 100     ],     [         'date' => "02.08.2023",         'qty' => 15,     ], ];  $dates1[] = [     [         'date' => "01.08.2023",         'qty' => 0     ],     [         'date' => "03.08.2023",         'qty' => 25,     ], ];   $result = [     [         'date' => "01.08.2023",         'qty' => 100     ],     [         'date' => "02.08.2023",         'qty' => 15,     ],     [         'date' => "03.08.2023",         'qty' => 25,     ], ];

    $dates1[] = [ [ 'date' => "01.08.2023", 'qty' => 100 ], [ 'date' => "02.08.2023", 'qty' => 15, ], ]; $dates1[] = [ [ 'date' => "01.08.2023", 'qty' => 0 ], [ 'date' => "03.08.2023", 'qty' => 25, ], ]; $result = [ [ 'date' => "01.08.2023", 'qty' => 100 ], [ 'date' => "02.08.2023", 'qty' => 15, ], [ 'date' => "03.08.2023", 'qty' => 25, ], ];

  • Слава, ну и вам уже сказали - используйте цикл. хотите выпендриться - используйте один цикл на оба массива у вас данные упорядоченны как я вижу, ничего не мешает.
  • Дмитрий, вы правы. Но в данном случае я ищу вот такой способ чтоб обойтись меньшим числом циклов.

    у меня решение получилось таким:

    один внешний цикл. перебирает один массив. и внутри цикла используется второй массив преобразованный в коллекцию. и при помощи функции filter ищется элемент с таким же полем "date".

    если находим элемент, то объединяем элементы, то в третий массив добавляем этот элемент суммируя qty.
    а если не находим, то записываем элемент внешнего цикла.

  • Слава, нагуглите merge join
  • Слава, ну и как нибудь избавьтесь от мысли "ну через циклы то каждый может. Но это джуновский подход.". Это ровно выдает из вас джуна - слабая надежда что какие то волшебные функции избавят вас от работы
  • Слава, джуновский подход - это экономить на строчках и вымучивать неочевидные коллбеки там, где проблема решается банальным циклом, очевидным для читающего код.
    А ламерский подход - это формулировать задачу про

    price и quantity

    и при этом давать в качестве примера

    [         'date' => "01.08.2023",         'qty' => 100     ]

    [ 'date' => "01.08.2023", 'qty' => 100 ]

    и даже не задуматься о том, могут даты продублироваться или нет.
    Подход профи - напротив, задуматься, что будет, КОГДА они задублируются, ХОТЯ вы были уверены, что этого не может быть.

  • Слава, ваша идея плоха с array_filter потому что будет использовать ровно тот же цикл. если вы цикл не видите - это не значит что его нет. Ровно по этому забудьте о всяком волшебстве и работайте нормально.

    собственно стоит загуглить 3 варианта соединения - nested loop join, merge join, hash join и это в разы будет лучше чем заучивание каких либо глупостей в виде методов коллекций ларки. заодно будете лучше понимать explain запросов к бд.

  • Дмитрий, ясно. мне это нужно было вот для чего. В БД хранятся показатели только за определенные данные. а мне надо возвращать на фронтэнд показатели за каждый день и в том случае, если за этот день нет записи в базе, то выдавать нули. вот я и реализовал массив на каждую дату и потом сопоставляю его с тем что есть в базе. а сложение должно было быть просто способом объединить записи - думал просто одной функцией всё можно сделать.

    а так то да - в цикле всё легко делается.

  • Слава, похоже такое себе придумали. База какая? И какая версия?
  • Adamos, не задублируются они. проверка стоит на уровне бд.
  • Дмитрий, pq. просто чтоб лишних записей с нулевыми показателями не хранить в базе.
  • Дмитрий, вы посмотрите что мне ответили в ответах. какие там изящные сениорские функции.
  • Слава,

    1. и в последний раз: сеньора отличает не знание и использование каких то конкретных инструментов, а знание как работают эти инструменты и следовательно когда стоит их использовать, а когда стоит выбрать другие. Собственно если вы в ответах начнете усложнять контекст задачи а именно к примеру укажите что массивы большие, и сортированные, а процесс частый - эти красивые комбайны быстро трансформируются в нечто другое - похожее на то что я рекомендовал вам почитать. Ибо скорее всего поймут что такое количество циклов здесь не нужно. Но больше я эту тему поднимать не буду - мне лень, подожду когда вы попадете в более менее нормальную контору и вас там за эту глупость показательно накажут.

    2. И если у вас postgresql вы занимаетесь фигней. ибо в нем есть прекрасная функция generate_series

    select   dates, colaesce(quantity, 0) from   generate_series('2023-01-01', '2023-12-31', interval '1 day') as dates left join table_with_data on dates = table_with_data.date;

    select dates, colaesce(quantity, 0) from generate_series('2023-01-01', '2023-12-31', interval '1 day') as dates left join table_with_data on dates = table_with_data.date;

    сразу из дб вернет вам то что нужно и весь этот гемморой уйдет в историю

  • function merge($arrs, $idKey, ...$sumKeys) {   $result = [];    foreach (array_merge(...$arrs) as $n) {     $id = $n[$idKey];     $result[$id] ??= array_merge($n, array_combine($sumKeys, array_fill(0, count($sumKeys), 0)));      foreach ($sumKeys as $k) {       $result[$id][$k] += $n[$k];     }   }    return array_values($result); }   $result = merge($dates1, 'date', 'qty');

    function merge($arrs, $idKey, ...$sumKeys) { $result = []; foreach (array_merge(...$arrs) as $n) { $id = $n[$idKey]; $result[$id] ??= array_merge($n, array_combine($sumKeys, array_fill(0, count($sumKeys), 0))); foreach ($sumKeys as $k) { $result[$id][$k] += $n[$k]; } } return array_values($result); } $result = merge($dates1, 'date', 'qty');

    function merge($arr) { 	$map = array_reduce(array_merge(...$arr), function($map, $item) { 		$map[$item["date"]] = ($map[$item["date"]] ?? 0) + $item["qty"]; 		 		return $map; 	}, []); 	 	return array_map(function($key) use ($map) { 		return [ 			"date" => $key, 			"qty" => $map[$key], 		]; 	}, array_keys($map)); }

    function merge($arr) { $map = array_reduce(array_merge(...$arr), function($map, $item) { $map[$item["date"]] = ($map[$item["date"]] ?? 0) + $item["qty"]; return $map; }, []); return array_map(function($key) use ($map) { return [ "date" => $key, "qty" => $map[$key], ]; }, array_keys($map)); }

    Упарываться можно по разному, например смапить по ключу, а потом переформировать в нужную структуру.

    Нужно решить такую задачу?

    Опишите проблему, и специалист поможет с настройкой, исправлением ошибки или доработкой сайта. Подберём понятный план работ без лишней переписки.

    Заказать помощь
    Лучший ответ
    1
    Павел Админов Ответ

    Для объединения ассоциативных массивов по значениям определенных полей, можно воспользоваться функцией array_merge_recursive(). Эта функция объединяет два или более массивов рекурсивно, сохраняя все значения и структуру массивов.

    Пример использования:

    $array1 = array(
        array("id" => 1, "name" => "John"),
        array("id" => 2, "name" => "Alice")
    );
     
    $array2 = array(
        array("id" => 2, "age" => 25),
        array("id" => 1, "age" => 30)
    );
     
    $result = array();
     
    foreach ($array1 as $item1) {
        foreach ($array2 as $item2) {
            if ($item1['id'] == $item2['id']) {
                $result[] = array_merge_recursive($item1, $item2);
                break;
            }
        }
    }
     
    print_r($result);

    $array1 = array( array("id" => 1, "name" => "John"), array("id" => 2, "name" => "Alice") ); $array2 = array( array("id" => 2, "age" => 25), array("id" => 1, "age" => 30) ); $result = array(); foreach ($array1 as $item1) { foreach ($array2 as $item2) { if ($item1['id'] == $item2['id']) { $result[] = array_merge_recursive($item1, $item2); break; } } } print_r($result);

    В данном примере мы объединяем массивы $array1 и $array2 по значению поля 'id'. Мы проходим по каждому элементу массива $array1 и сравниваем его 'id' со всеми элементами массива $array2. При совпадении значений 'id' мы объединяем элементы в новый массив $result с помощью функции array_merge_recursive().

    После выполнения этого кода, в переменной $result будет содержаться объединенный массив, который можно использовать дальше в программе.

    Другие ответы (0)

    Пока нет других ответов. Будьте первым, кто поможет автору.

    Ответить на вопрос

    комментарий

    Ваш адрес email не будет опубликован. Обязательные поля помечены *

    Вам также может быть интересно