Как эффективно объединить два (или более) ассоциативных массива с общими ключами - PullRequest
1 голос
/ 26 февраля 2011

В более общем смысле, скажем, у нас есть два списка разной длины с одним общим атрибутом:

list1: {
         {"orderID":1234, "FirstName":"shaheeb", "LastName":"roshan"},
         {"orderID":9183, "FirstName":"robert", "LastName":"gibbons"},
         {"orderID":2321, "FirstName":"chester"},
       }
list2: {
         {"orderID":1234, "cell":"555-555-5555", "email":"roshan@fake.com"},
         {"orderID":2321, "email":"chester@fake.com"},
       }

Я бы хотел объединить их в:

list3: {
         {"orderID":1234, "FirstName":"shaheeb", "LastName":"roshan", "cell":"555-555-5555", "email":"roshan@fake.com"},
         {"orderID":9183, "FirstName":"robert", "LastName":"gibbons"},
         {"orderID":2321, "FirstName":"chester", "email":"chester@fake.com"},
       }

Я в первую очередьРазработчик PHP, и я придумал следующее:

function mergeArrays($a1, $a2) {
    $larger = (count($a1) > count($a2)) ? $a1 : $a2;
    $smaller = ($larger == $a1) ? $a2 : $a1;
    $combinedArray = array();
    foreach ($larger AS $key=>$largerSet) {
        $combinedRow = array();
        if (isset ($smaller[$key]) ) {
            $combinedRow = $largerSet + $smaller[$key];
            $combinedArray[$key] = $combinedRow;
        }else {
            $combinedArray[$key] = $largerSet;
        }
    }
    return ($combinedArray);
}

Если проверено со следующим:

$array1 = array("12345"=>array("OrderID"=>12345, "Apt"=>"blue"));
$array2 = array(
                "12345"=>array("OrderID"=>12345, "AnotherCol"=>"Goons", "furtherColumns"=>"More Data"),
                "13433"=>array("OrderID"=>32544, "Yellow"=>"Submarine")
            );

mergeArrays ($ array1, $ array2) выдает следующее:

array(2) {
  [12345]=>
  array(4) {
    ["OrderID"]=>
    int(12345)
    ["AnotherCol"]=>
    string(5) "Goons"
    ["furtherColumns"]=>
    string(9) "More Data"
    ["Apt"]=>
    string(4) "blue"
  }
  [13433]=>
  array(2) {
    ["OrderID"]=>
    int(32544)
    ["Yellow"]=>
    string(9) "Submarine"
  }
}

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

В качестве учебного материала мне любопытно, воспользуются ли эксперты Python этой возможностью, чтобы появитьсянас фолк фолк :).В этом отношении мне любопытно, сможет ли Excel / VBA справиться с этим.Именно здесь я начал пытаться решить эту проблему с мыслью, что «несомненно, Excel справится со списками!».

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

Ваши мысли очень ценятся.

Спасибо!

SR

Ответы [ 3 ]

4 голосов
/ 26 февраля 2011

Для общего решения в Python, для любого количества списков:

orders = defaultdict(dict)
for order_list in order_lists:
    for order in order_list:
        orders[order['orderID']].update(order)

Смотрите, как работает онлайн: ideone

2 голосов
/ 26 февраля 2011

Общее решение, которое может объединять любое количество диктов (или список диктов - если у вас более одного списка, просто сложите их вместе перед вызовом функции):

from collections import defaultdict

def merge_dicts_by_key(key, *dicts):
    return reduce(lambda acc,val: acc[val[key]].update(val) or acc,
                  dicts,
                  defaultdict(dict))

Звоните так:

merge_dicts_by_key('orderId', dict1, dict2, dict3)

или, если у вас есть списки диктов:

merge_dicts_by_key('orderId', *list_of_dicts)
merge_dicts_by_key('orderId', *(list1 + list2))
1 голос
/ 26 февраля 2011

Ну, вы всегда можете заменить свою функцию на array_merge_recursive.

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