【问题标题】:How do I sum the values in an array of maps in jq?如何对 jq 中的地图数组中的值求和?
【发布时间】:2015-04-13 14:32:11
【问题描述】:

给定以下格式的 JSON 流:

{ "a": 10, "b": 11 } { "a": 20, "b": 21 } { "a": 30, "b": 31 }

我想将每个对象中的值相加并输出一个对象,即:

{ "a": 60, "b": 63 }

我猜这可能需要将上面的对象列表展平为 [name, value] 对的数组,然后使用 reduce 对这些值求和,但使用 reduce 的语法文档很糟糕。

【问题讨论】:

    标签: json sum key jq


    【解决方案1】:

    除非您的 jq 有 inputs,否则您将不得不使用 -s 标志来吞食对象。然后你必须做大量的操作:

    1. 每个对象都需要映射到键/值对
    2. 将这些对展平为单个数组
    3. 按键组合成对
    4. 将每个组的值累加到单个键/值对中
    5. 将这些对映射回一个对象
    map(to_entries)
        | add
        | group_by(.key)
        | map({
              key: .[0].key,
              value: map(.value) | add
          })
        | from_entries
    

    使用 jq 1.5,这可以大大改善:您可以摆脱啜饮,直接阅读inputs

    $ jq -n '
    reduce (inputs | to_entries[]) as {$key,$value} ({}; .[$key] += $value)
    ' input.json
    

    由于我们只是累加每个对象中的所有值,因此只需遍历所有输入的键/值对并将它们全部相加会更容易。

    【讨论】:

    • 啊,group_by 是我所缺少的,我在文档中忽略了它。此外,我得到了生成源数据的工具,以将其作为单个 JSON 流输出,因此不需要“-s”。我所做的唯一其他调整是使用“扁平化”而不是“添加”。感谢您的回答,它就在:-)
    • Reduce 太棒了!我正在为它如何支持 2 种方法(instance 的 sum 和 avg)而苦苦挣扎credits":0,"minutes":0}; ."credits" += $item.credits; ."minutes" += $item.amount /1000/60 )
    • @Eddie:分号用于分隔函数调用的参数。你在那里使用它的方式应该是管道,它会像你期望的那样工作。
    • 不应该jq -s 'reduce (.[] | to_entries[]) ...jq -n 'reduce (inputs | to_entries[]) ... 一样好用吗?我缺少对映射的需求,group_by 等。或者缺少 inputs 是否意味着在 -n 示例中缺少其他构造的 jq 版本?
    • 对于那些已经在 jq 中使用流的人,请确保在 map(to_entries) 之前在流周围使用 [ ... ] 将其转换为数组。
    【解决方案2】:

    另一种很好地说明 jq 强大功能的方法是使用名为“sum”的过滤器,定义如下:

    def sum(f): reduce .[] as $row (0; . + ($row|f) );
    

    为了解决手头的特定问题,可以使用上面提到的-s (--slurp) 选项以及以下表达式:

    {"a": sum(.a), "b": sum(.b) }  # (2)
    

    标记为 (2) 的表达式只计算两个指定的和,但它很容易概括,例如如下:

    # Produce an object with the same keys as the first object in the 
    # input array, but with values equal to the sum of the corresponding
    # values in all the objects.
    def sumByKey:
      . as $in
      | reduce (.[0] | keys)[] as $key
        ( {}; . + {($key): ($in | sum(.[$key]))})
    ;
    

    【讨论】:

      【解决方案3】:

      在列出来自 GitHub 的所有工件时,我遇到了同样的问题(有关详细信息,请参阅 here)并想对它们的大小求和。

      curl https://api.github.com/repos/:owner/:repo/actions/artifacts \
           -H "Accept: application/vnd.github.v3+json" \
           -H "Authorization:  token <your_pat_here>" \
           | jq '.artifacts | map(.size_in_bytes) | add'
      

      输入:

      {
        "total_count": 3,
        "artifacts": [
          {
            "id": 0000001,
            "node_id": "MDg6QXJ0aWZhY3QyNzUxNjI1",
            "name": "artifact-1",
            "size_in_bytes": 1,
            "url": "https://api.github.com/repos/:owner/:repo/actions/artifacts/2751625",
            "archive_download_url": "https://api.github.com/repos/:owner/:repo/actions/artifacts/2751625/zip",
            "expired": false,
            "created_at": "2020-03-10T18:21:23Z",
            "updated_at": "2020-03-10T18:21:24Z"
          },
          {
            "id": 0000002,
            "node_id": "MDg6QXJ0aWZhY3QyNzUxNjI0",
            "name": "artifact-2",
            "size_in_bytes": 2,
            "url": "https://api.github.com/repos/:owner/:repo/actions/artifacts/2751624",
            "archive_download_url": "https://api.github.com/repos/:owner/:repo/actions/artifacts/2751624/zip",
            "expired": false,
            "created_at": "2020-03-10T18:21:23Z",
            "updated_at": "2020-03-10T18:21:24Z"
          },
          {
            "id": 0000003,
            "node_id": "MDg6QXJ0aWZhY3QyNzI3NTk1",
            "name": "artifact-3",
            "size_in_bytes": 3,
            "url": "https://api.github.com/repos/docker/mercury-ui/actions/artifacts/2727595",
            "archive_download_url": "https://api.github.com/repos/:owner/:repo/actions/artifacts/2727595/zip",
            "expired": false,
            "created_at": "2020-03-10T08:46:08Z",
            "updated_at": "2020-03-10T08:46:09Z"
          }
        ]
      }
      

      输出:

      6
      

      【讨论】:

      • 使用 -s 标志使其工作:jq -s '.artifacts | map(.size_in_bytes) | add'
      猜你喜欢
      • 2022-08-17
      • 2019-02-03
      • 2020-12-08
      • 2022-11-18
      • 2022-07-20
      • 2016-09-05
      • 1970-01-01
      • 1970-01-01
      • 2011-12-17
      相关资源
      最近更新 更多