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

如何使用jq使用子值对象的键对json对象进行分组

  •  0
  • Evadore  · 技术社区  · 1 年前

    我有一个json文件,格式如下

    {
      "hello": [
        {
          "name": "var1",
          "value": "1234"
        },
        {
          "name": "var2",
          "value": "2356"
        },
        {
          "name": "var3",
          "value": "2356"
        }
      ],
      "hi": [
        {
          "name": "var1",
          "value": "3412"
        },
        {
          "name": "var2",
          "value": "2563"
        },
        {
          "name": "var3",
          "value": "4256"
        }
      ],
      "bye": [
        {
          "name": "var1",
          "value": "1294"
        },
        {
          "name": "var2",
          "value": "8356"
        },
        {
          "name": "var3",
          "value": "5356"
        }
      ]
    }
    

    我想把这个对象转换成这种格式

    {
      "output": [
        {
          "var1": {
            "hello": "1234",
            "hi": "3412",
            "bye": "1294"
          }
        },
        {
          "var2": {
            "hello": "2356",
            "hi": "2563",
            "bye": "8356"
          }
        },
        {
          "var3": {
            "hello": "2356",
            "hi": "4256",
            "bye": "5356"
          }
        }
      ]
    }
    

    到目前为止,我已经尝试了多种方法,使用jq中的toentries和map函数来创建输出变量中的内容 jq 'to_entries | map(.value[]| . += {"key_v" : (.key)} )' input.json > output.json 这是我最接近的解决方案

    • 提取密钥并添加到对象的键值对
    • 使用map(select())按键分组 但我在这两个步骤中都遇到了错误,比如不能用字符串名称或字符串值对数组进行索引。
    0 回复  |  直到 1 年前
        1
  •  3
  •   knittl    1 年前

    它不会赢得选美比赛,但它很有效:

    with_entries(.value |= from_entries)
    | with_entries(.key as $key | .value[] |= {($key):.})
    | reduce .[] as $item ({}; . * $item)
    | {output: to_entries | map({(.key):.value})}
    

    只需一次呼叫 with_entries :

    with_entries(.key as $key | .value |= (from_entries | map_values({($key):.})))
    | reduce .[] as $item ({}; . * $item)
    | {output: to_entries | map({(.key):.value})}
    

    输出

    {
      "output": [
        {
          "var1": {
            "hello": "1234",
            "hi": "3412",
            "bye": "1294"
          }
        },
        {
          "var2": {
            "hello": "2356",
            "hi": "2563",
            "bye": "8356"
          }
        },
        {
          "var3": {
            "hello": "2356",
            "hi": "4256",
            "bye": "5356"
          }
        }
      ]
    }
    
        2
  •  3
  •   peak    1 年前

    如果使用以下面向流的“聚结”函数,很容易获得简单的解决方案:

    # s is assumed to be a stream of objects for which
    # the values for each distinct key are summable.
    # Output: a single object formed by adding 
    # the $v values of each distinct key.
    def coalesce(s):
      reduce (s | to_entries[]) as {key: $k, value: $v} ({};
        .[$k] += $v);
    

    现在的解决方案很简单:

    coalesce(to_entries[]
             | .key as $key
             | .value[]
             | {(.name): {($key): .value}})
    | {output: [.]}
    
        3
  •  2
  •   Philippe    1 年前

    这产生了预期结果:

    { output:
        to_entries |
        map(.key as $key|.value|map(.nn=.name|.name=$key)) |
        add |
        group_by(.nn) |
        map({(first|.nn) : from_entries})
    }