Search code examples
jsonnet

How to join two list into one on some common fields?


I want to join two list into one using deep copy.
E.g.

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"]}
]

I tried std.mergePatch but it just overrides the previous list. Thanks,


Solution

  • Copying below a possible solution, which "unrolls" the list(s) down to single key-value entries, then aggregate them into the manifested object, note that the code is long because of detailed comments.

    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