代码之家  ›  专栏  ›  技术社区  ›  larsks

用jsonnet合并任意键的数组值

  •  0
  • larsks  · 技术社区  · 2 年前

    我在一个jsonnet文档中有一个配置文件列表 main.jsonnet ,如下所示:

    local configFiles = [
      import "file1.jsonnet",
      import "file2.jsonnet",
      import "file3.jsonnet",
    ];
    
    {
    # ...something goes here...
    }
    

    导入的文件包含任意的密钥集(也就是说,我们事先不知道密钥的完整列表)。对于这个例子, file1.jsonnet 看起来像:

    {
      names: ["alice", "bob"],
      colors: ["red"],
    }
    

    file2.jsonnet 看起来像:

    {
      names: ['mallory'],
      animals: ['cow'],
    }
    

    file3.jsonnet 看起来像:

    {
      names: ['angus'],
      colors: ['brown'],
      animals: ['horse'],
      size: ['medium'],
    }
    

    我想替换 # ...something goes here... 使用适当的代码生成:

    {
      names: ["alice", "bob", "mallory", "angus"],
      colors: ["red", "brown"],
      animals: ["cow", "horse"],
      size: ["medium"],
    }
    

    这将是一个简单的迭代解决方案很容易;在Python中,我可能会写以下内容:

    import _jsonnet as jsonnet
    import json
    
    merged = {}
    fileNames = ["file1.jsonnet", "file2.jsonnet", "file3.jsonnet"]
    configFiles = [json.loads(jsonnet.evaluate_file(fn)) for fn in fileNames]
    
    for configFile in configFiles:
        for k, v in configFile.items():
            merged[k] = merged.get(k, []) + v
    
    print(json.dumps(merged, indent=2))
    

    逻辑看起来很简单,但jsonnet中唯一可用的迭代器是数组和对象的理解,这似乎更棘手。我试过了:

    {
        [k]: if self[k] then self[k] + configFile[k] else configFile[k]
        for configFile in configFiles
        for k in std.objectFields(configFile)
    }
    

    但结果是:

    RUNTIME ERROR: duplicate field name: "names"
            main.jsonnet:(7:1)-(11:2)
    
    1 回复  |  直到 2 年前
        1
  •  1
  •   jjo    2 年前

    一个非常有用的std函数,可以克服 [keyName] 重复问题是 std.foldl .

    下面的例子实现了将数组与其合并,为了简单起见,我嵌入了 configFiles 在同一src中(即没有 import 这将在这种情况下实现相同的效果)。

    来源:foo.jsonet

    local f1 = {
      names: ['alice', 'bob'],
      colors: ['red'],
    };
    local f2 = {
      names: ['mallory'],
      animals: ['cow'],
    };
    local f3 = {
      names: ['angus'],
      colors: ['brown'],
      animals: ['horse'],
      size: ['medium'],
    };
    local configFiles = [f1, f2, f3];
    
    // Use std.foldl() which will call the function() one for each element in the array,
    // thus somehow "avoiding" the `[keyName]` duplicate issue
    std.foldl(
      function(acc, x) acc {
        [kv.key]+: kv.value
        for kv in std.objectKeysValues(x)
      },
      configFiles,
      {}
    )
    

    输出

    $ jsonnet foo.jsonnet
    {
       "animals": [
          "cow",
          "horse"
       ],
       "colors": [
          "red",
          "brown"
       ],
       "names": [
          "alice",
          "bob",
          "mallory",
          "angus"
       ],
       "size": [
          "medium"
       ]
    }
    
    推荐文章