【问题标题】:How to merge and aggregate values in 2 JSON files using jq?如何使用 jq 合并和聚合 2 个 JSON 文件中的值?
【发布时间】:2021-09-10 20:28:07
【问题描述】:

我在 shell 脚本中使用 jq 来操作 JSON 文件。

我有 2 个文件,我想将它们合并到一个文件中,同时在名称/值对中的名称相同时聚合(求和)这些值。

举个例子:

Input1.json

[
  {
    "A": "Name 1",
    "B": "1.1",
    "C": "2"
  },
  {
    "A": "Name 2",
    "B": "3.2",
    "C": "4"
  }
]

Input2.json

[
  {
    "A": "Name 2",
    "B": "5",
    "C": "6"
  },
  {
    "A": "Name 3",
    "B": "7",
    "C": "8"
  }
]

预期结果:

输出.json

[
  {
    "A": "Name 1",
    "B": "1.1",
    "C": "2"
  },
  {
    "A": "Name 2",
    "B": "8.2",
    "C": "10"
  },
  {
    "A": "Name 3",
    "B": "7",
    "C": "8"
  }
]

我可以使用jq 以外的其他工具,但我更愿意最终将解决方案包含在我可以从终端调用的 shell 脚本中。

感谢任何帮助。谢谢。

【问题讨论】:

  • 您是否需要它与任意键一起使用,或者总是可以假设A 是用于聚合的键,BC 是要添加的整数,没有别的东西存在?
  • @CharlesDuffy 您可以假设 A 是使用的关键。 B 和 C 是应该相加的十进制数(我更新了示例以包含一些十进制数)。

标签: json shell command-line merge jq


【解决方案1】:

我可以使用 jq 以外的其他工具,但我更愿意最终将解决方案包含在我可以从终端调用的 shell 脚本中。

你可以试试 JSON 解析器

$ xidel -se '
  array{
    let $src:=(json-doc("Input1.json")(),json-doc("Input2.json")())
    for $name in distinct-values($src/A)
    let $obj:=$src[A=$name]
    return
    if (count($obj) gt 1) then
      map:merge(
        $obj[1]() ! {
          .:if ($obj[1](.) castable as decimal) then
            string($obj[1](.) + $obj[2](.))
          else
            $obj[1](.)
        }
      )
    else
      $obj
  }
'

Intermediate steps.

【讨论】:

    【解决方案2】:

    jq 非常适合解决这样的问题:

    $ jq -n '
    reduce inputs[] as {$A,$B,$C} ({};
        .[$A] |= {
            $A,
            B: (.B + ($B|tonumber)),
            C: (.C + ($C|tonumber))
        }
    )
    | map({
        A,
        B: (.B|tostring),
        C: (.C|tostring)
      })
    ' input1.json input2.json
    

    第一个reduce 创建一个从不同“A”值到聚合结果对象的映射。然后给定映射,转换回结果对象数组,调整结果的类型。

    jqplay

    【讨论】:

      【解决方案3】:

      这是一种方法,但还有其他方法:

      jq -s '
       def to_n: tonumber? // null;
       def merge_values($x;$y): 
         if $x == $y then $x
         elif $x == null then $y
         elif $y == null then $x
         else ($x|to_n) as $xn
         | if $xn then ($y|to_n) as $yn | ($xn+$yn)|tostring
           else [$x, $y]
           end
         end;
       def merge($x;$y):
         reduce ($x + $y |keys_unsorted)[] as $k (null;
           .[$k] = merge_values($x[$k]; $y[$k]) );
      
         
      
       INDEX(.[0][]; .A) as $in1
       | INDEX(.[1][]; .A) as $in2
       | ($in1 + $in2|keys_unsorted) as $keys
       | reduce $keys[] as $k ([];
           . + [merge($in1[$k]; $in2[$k]) ])
      
          
          
      ' input1.json inut2.json
      

      【讨论】:

        猜你喜欢
        • 2013-11-01
        • 1970-01-01
        • 2019-06-11
        • 1970-01-01
        • 1970-01-01
        • 2022-10-24
        • 1970-01-01
        • 2022-06-11
        • 1970-01-01
        相关资源
        最近更新 更多