36

次の形式の JSON ストリームがあるとします。

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

各オブジェクトの値を合計して、単一のオブジェクトを出力したいと思います。

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

これにはおそらく、上記のオブジェクトのリストをペアの配列にフラット化し、[name, value]使用して値を合計する必要があると思いreduceますが、使用の構文のドキュメントreduceは悲惨です。

4

3 に答える 3

37

jq に が含まれていない限りinputs、フラグを使用してオブジェクトを丸呑みする必要があります-s。次に、かなりの量の操作を行う必要があります。

  1. 各オブジェクトをキーと値のペアにマッピングする必要があります
  2. ペアを 1 つの配列にフラット化する
  3. ペアをキーでグループ化する
  4. 値を蓄積する各グループを 1 つのキーと値のペアにマップします。
  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

各オブジェクトのすべての値を単純に累積しているので、すべての入力のキーと値のペアを実行して、それらをすべて加算する方が簡単です。

于 2015-02-12T18:52:57.003 に答える
13

GitHub からすべての成果物をリストするときに同じ質問に直面し (詳細については、こちらを参照)、それらのサイズを合計したいと考えています。

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
于 2020-03-11T18:57:16.383 に答える
9

jq の能力を非常によく示す別のアプローチは、次のように定義された「sum」という名前のフィルターを使用することです。

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

目の前の特定の問題を解決するには、-s上記のように (--slurp) オプションを次の式とともに使用できます。

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

(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]))})
;
于 2015-02-16T06:08:32.197 に答える