Я хочу объединить два списка в один, используя глубокую копию.
Например.
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"]}
]
Скопировав ниже возможное решение, которое «разворачивает» список (списки) до отдельных записей «ключ-значение», а затем объединяет их в манифестируемый объект, обратите внимание, что код длинный из-за подробных комментариев.
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