How to efficiently combine two (or more) associative arrays with common keys
More generally, let's say we have two lists of different lengths with one common attribute:
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"},
}
I would like these combined into:
list3: {
{"orderID":1234, "FirstName":"shaheeb", "LastName":"roshan", "cell":"555-555-5555", "email":"roshan@fake.com"},
{"orderID":9183, "FirstName":开发者_如何学C"robert", "LastName":"gibbons"},
{"orderID":2321, "FirstName":"chester", "email":"chester@fake.com"},
}
I'm primarily a PHP developer, and I came up with the following:
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);
}
If tested with the following:
$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")
);
The mergeArrays($array1, $array2) outputs the following:
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"
}
}
But I just don't feel like this is the most elegant solution. For example, I should be able to combine n number of arrays. Not really sure how I would accomplish that. Also, just looking at that bit of code, I'm fairly certain there are far more effective ways to accomplish this requirement.
As a learning point, I am curious whether python experts would take this opportunity to show up us PHP folk :). For that matter, I am curious whether Excel/VBA can even handle this. That is where I started trying to solve this problem with the thought that "surely excel can handle lists!".
I am fully aware that there are many many variations of this question around SO. I have looked at several of these, and still felt that I should try my version out here.
Your thoughts are most appreciated.
Thank you!
SR
For a general solution in Python, for any number of lists:
orders = defaultdict(dict)
for order_list in order_lists:
for order in order_list:
orders[order['orderID']].update(order)
See it working online: ideone
A generic solution that can merge any number of dicts (or a list of dicts - if you have more than one list, just add them together before calling the function):
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))
Call like so:
merge_dicts_by_key('orderId', dict1, dict2, dict3)
or, if you have lists of dicts:
merge_dicts_by_key('orderId', *list_of_dicts)
merge_dicts_by_key('orderId', *(list1 + list2))
Well, you could always replace your function with array_merge_recursive
.
精彩评论