如何在某些公共字段上将两个列表合并为一个列表?
How to join two list into one on some common fields?
我想使用深拷贝将两个列表合二为一。
例如
list1:
[
{"key1":["val1"]},
{"key2":["val2", "val3"]}
]
list2:
[
{"key2":["val2", "val4"]},
{"key3":["val5"]}
]
I want the output to be :
[
{"key1":["val1"]},
{"key2":["val2", "val3", "val4"]}
{"key3":["val5"]}
]
我试过 std.mergePatch 但它只是覆盖了之前的列表。
谢谢,
你有相当复杂的结构要合并,没有标准函数在这里有帮助,自定义编写的函数将在很大程度上取决于你想要什么
如果您不介意数组元素的顺序,并且键不重复,则此方法可行:
local
// Extract "key" out of {key: ...}
unionName(u) = assert std.length(u) == 1; std.objectFields(u)[0],
// Convert [{a: ...}, {b: ...}] to {a: ..., b: ...}
mergeArrsToObject(arr) = {
[unionName(el)]: el[unionName(el)] for el in arr
},
// Inverse of mergeArrsToObject
splitArrsFromObject(obj) = [
{[key]: obj[key]} for key in std.objectFields(obj)
],
// Custom merge logic implemented for object:
// here I add values from both, and then sort & deduplicate
mergeObjects(a, b) = {
[key]: std.set(std.get(a, key, []) + std.get(b, key, []))
for key in std.set(std.objectFields(a) + std.objectFields(b))
},
merge(a, b) = splitArrsFromObject(mergeObjects(
mergeArrsToObject(a),
mergeArrsToObject(b),
))
;
merge([
{"key1":["val1"]},
{"key2":["val2", "val3"]}
], [
{"key2":["val2", "val4"]},
{"key3":["val5"]}
]) == [
{"key1":["val1"]},
{"key2":["val2", "val3", "val4"]},
{"key3":["val5"]}
]
在下面复制一个可能的解决方案,将列表“展开”为单个 key-value 条目,然后将它们聚合到显示的对象中,请注意,由于详细的注释,代码很长。
local list1 = [
{ key1: ['val1'] },
{ key2: ['val2', 'val3'] },
];
local list2 = [
{ key2: ['val2', 'val4'] },
{ key3: ['val5'] },
];
// Hash key for the `seen` dictionary
local hash(kv) = std.md5(std.toString(kv));
// Loop over the passed array of objs, aggregating each final/"leaf" KV pair,
// but only if not seen before
local mergeLists(lists) = std.foldl(
function(mergedObj, kv) mergedObj {
ret+: if (hash(kv) in mergedObj.seen) then {} else {
[kv.key]+: [kv.value],
},
seen+:: {
[hash(kv)]: true,
},
},
// "Unroll" the (sum of) list(s), we need 3 loops:
// 1) main list
// 2) each entry's object from 1)
// 3) each "final" list of values
// -> convert them into single Key-Value (mini) objects
[
{ key: k, value: v }
for list in lists
for k in std.objectFields(list)
for v in list[k]
],
{ seen:: {} },
);
mergeLists(list1 + list2).ret
我想使用深拷贝将两个列表合二为一。
例如
list1:
[
{"key1":["val1"]},
{"key2":["val2", "val3"]}
]
list2:
[
{"key2":["val2", "val4"]},
{"key3":["val5"]}
]
I want the output to be :
[
{"key1":["val1"]},
{"key2":["val2", "val3", "val4"]}
{"key3":["val5"]}
]
我试过 std.mergePatch 但它只是覆盖了之前的列表。 谢谢,
你有相当复杂的结构要合并,没有标准函数在这里有帮助,自定义编写的函数将在很大程度上取决于你想要什么
如果您不介意数组元素的顺序,并且键不重复,则此方法可行:
local
// Extract "key" out of {key: ...}
unionName(u) = assert std.length(u) == 1; std.objectFields(u)[0],
// Convert [{a: ...}, {b: ...}] to {a: ..., b: ...}
mergeArrsToObject(arr) = {
[unionName(el)]: el[unionName(el)] for el in arr
},
// Inverse of mergeArrsToObject
splitArrsFromObject(obj) = [
{[key]: obj[key]} for key in std.objectFields(obj)
],
// Custom merge logic implemented for object:
// here I add values from both, and then sort & deduplicate
mergeObjects(a, b) = {
[key]: std.set(std.get(a, key, []) + std.get(b, key, []))
for key in std.set(std.objectFields(a) + std.objectFields(b))
},
merge(a, b) = splitArrsFromObject(mergeObjects(
mergeArrsToObject(a),
mergeArrsToObject(b),
))
;
merge([
{"key1":["val1"]},
{"key2":["val2", "val3"]}
], [
{"key2":["val2", "val4"]},
{"key3":["val5"]}
]) == [
{"key1":["val1"]},
{"key2":["val2", "val3", "val4"]},
{"key3":["val5"]}
]
在下面复制一个可能的解决方案,将列表“展开”为单个 key-value 条目,然后将它们聚合到显示的对象中,请注意,由于详细的注释,代码很长。
local list1 = [
{ key1: ['val1'] },
{ key2: ['val2', 'val3'] },
];
local list2 = [
{ key2: ['val2', 'val4'] },
{ key3: ['val5'] },
];
// Hash key for the `seen` dictionary
local hash(kv) = std.md5(std.toString(kv));
// Loop over the passed array of objs, aggregating each final/"leaf" KV pair,
// but only if not seen before
local mergeLists(lists) = std.foldl(
function(mergedObj, kv) mergedObj {
ret+: if (hash(kv) in mergedObj.seen) then {} else {
[kv.key]+: [kv.value],
},
seen+:: {
[hash(kv)]: true,
},
},
// "Unroll" the (sum of) list(s), we need 3 loops:
// 1) main list
// 2) each entry's object from 1)
// 3) each "final" list of values
// -> convert them into single Key-Value (mini) objects
[
{ key: k, value: v }
for list in lists
for k in std.objectFields(list)
for v in list[k]
],
{ seen:: {} },
);
mergeLists(list1 + list2).ret