使用 jq 区分 2 个数据系列值

Diff 2 data series values using jq

我不是专家 jq 用户,现在我已经尝试了很多不同的解决方案来解决我的问题。 我有一些属于特定版本的数据系列,我想计算它们之间的差异。基础数据将始终是一个包含两个元素的数组,其中包含数据系列的值。每个系列中值的数量可以变化,即 "valX" 值的数量不是恒定的。 结果应给出所有值 "ver1"-"ver2".

下面给出的结果数据是我想要最终结果的示例。如果值缺少尾随“0”,即 1.20 => 1.2 并且缺少前导零,即 0.01 => .01,那没问题。

示例JSON源数据:

[
  {
    "version": "ver1",
    "series": [
      {
        "id": "name1",
        "val1": "0.77",
        "val2": "1.34",
        "val3": "7.89",
        "val4": "6.00"
      },
      {
        "id": "name2",
        "val1": "0.34",
        "val2": "1.00",
        "val3": "12.15"
      }
    ]
  },
  {
    "version": "ver2",
    "series": [
      {
        "id": "name1",
        "val1": "0.35",
        "val2": "2.34",
        "val3": "6.50",
        "val4": "6.01"
      },
      {
        "id": "name2",
        "val1": "2.54",
        "val2": "0.55",
        "val3": "13.20"
      }
    ]
  }
]

我想要这样或非常相似的结果:

[
  {
    "id": "name1",
    "val1": "-0.42",
    "val2": "1.00",
    "val3": "-1.39",
    "val4": "0.01"
  },
  {
    "id": "name2",
    "val1": "-2.20",
    "val2": "-0.45",
    "val3": "1.05"
  }
]

任何有知识的人可以帮助我或至少让我朝着正确的方向前进?

首先,请修正您的示例中的 JSON。

其次,请放心,jq 非常适合这项任务,但它会 需要对 jq 有所了解才能设计出完整的解决方案 到问题。

自问题陈述 目前有点不明确,因为 SO 不是 一项免费的编程服务,我将在这里重点介绍 所需的关键功能,我认为是在寻找 具有相同 id 的两个对象之间的 "difference" 并且其其他键是数字字符串。

适合测试的数据

让我们从两个对象开始:

def s1: {
  "id": "name1",
  "val1": "0.77",
  "val2": "1.34",
  "val3": "7.89",
  "val4": "6.00"
  };

def s2: {
  "id": "name1",
  "val1": "0.35",
  "val2": "2.34",
  "val3": "6.50",
  "val4": "6.01"
  };

minus/2

这里最难的部分实际上是数值舍入,由内部函数round(n):

处理
# $a - $b
def minus($a; $b):
  def round(n):
    (if . < 0 then -1 else 1 end) as $s
    | $s*10*.*n
    | if (floor % 10) > 4 then (.+5) else . end
    | ./10 | floor/n | .*$s;

  def m($k): ($a[$k]|tonumber) - ($b[$k]|tonumber) | round(100);
  reduce ($a|keys_unsorted[]) as $k ({};
    if $k == "id" then .id = $a["id"]
    else .[$k] = m($k)
    end);

  minus(s2; s1)

(如果你真的想要两个数字之间的差异 要成为一个字符串,只需添加对 tostring 的调用。)

输出

{
  "id": "name1",
  "val1": -0.42,
  "val2": 1,
  "val3": -1.39,
  "val4": 0.01
}

提示

下面的 minus/2 调用在给定所提供的示例数据(更正后)时产生如下所示的结果:

map(.series) | transpose | map(minus(.[1]; .[0]))

结果:

[
  {
    "id": "name1",
    "val1": -0.42,
    "val2": 1,
    "val3": -1.39,
    "val4": 0.01
  },
  {
    "id": "name2",
    "val1": 2.2,
    "val2": -0.45,
    "val3": 1.05
  }
]

其余

...由您决定。这将取决于你想要多小心 匹配 "id" 值、处理边缘情况等。