json - 链接 JQ if : if A then B C else D end

标签 json bash jq swap

我想在 JQ if 语句中交换两个值。

给定以下 JSON:

{
  "food": {
    "fruit": [
      {
        "type": "apple",
        "count": 0
      },
      {
        "type": "banana",
        "count": 1
      },
      {
        "type": "orange",
        "count": 0
      }
    ]
  }
}

我想使用 JQ 根据条件交换两个对象的计数以产生以下结果。

{
  "food": {
    "fruit": [
      {
        "type": "apple",
        "count": 1
      },
      {
        "type": "banana",
        "count": 0
      },
      {
        "type": "orange",
        "count": 0
      }
    ]
  }
}

到目前为止,我可以将第一个水果从 0 改成 1

jq '
  if .food.fruit[] | select(.type=="apple") | .count == 0
  then
    .food.fruit[] | select(.type=="apple") | .count = 1
  else
    empty
  end
'

但我找不到正确的运算符来修改第二个。使用 JQ 是否可以实现类似以下内容?

jq '
  if .food.fruit[] | select(.type=="apple") | .count == 0
  then
    .food.fruit[] | select(.type=="apple") | .count = 1 &
    .food.fruit[] | select(.type=="banana") | .count = 0
  else
    empty
  end
'

我无法将其通过管道传输,因为那样会将单个水果对象通过管道传输到下一行,因此我不确定我应该在此处使用哪个运算符 - 如果甚至支持此类功能。 非常感谢任何帮助!

最佳答案

这是一个高效的解决方案,甚至可能不需要完全遍历fruit 数组一次。

想法是找到“apple”和“banana”对象的路径,这样交换就可以在没有任何进一步迭代的情况下完成。

为了提高效率,该解决方案使用 foreach 以便在找到“apple”和“banana”对象的路径后跳出(单个)循环。

.food.fruit |=
  ( . as $fruits
   | label $go
   | (foreach paths(objects) as $p ({}; 
      ($fruits|getpath($p)) as $x
      | if  ($x|.type)=="apple"
        then .apple  = {path: ($p + ["count"]), count: $x.count}
        elif ($x|.type) == "banana"
        then .banana = {path: ($p + ["count"]), count: $x.count}
        else . end;
      if .apple and .banana then ., break $go else empty end)
     ) as $dict
   | if $dict | .apple and .banana
     then setpath( $dict.apple.path;  $dict.banana.count) 
     |    setpath( $dict.banana.path; $dict.apple.count)
     else . end
 )

定义交换/4

上述解决方案可以抽象如下:

# Input: an array of JSON objects.
#
# In the objects with .[$f1key] == $f1 and .[$f1key] == $f2 if any,
# swap the values at .[$gkey].
# If the the array has more than one object with .[$f1key] == $f1,
# then the last one will be selected, and similarly with respect to $f2
#
def swap($f1; $f2; $fkey; $gkey):
  . as $in
  | label $go
  | (foreach paths(objects) as $p ({}; 
      ($in|getpath($p)) as $x
      | if  ($x[$fkey])==$f1
        then .f1 = {path: ($p + [$gkey]), count: $x[$gkey]}
        elif ($x[$fkey]) == $f2
        then .f2 = {path: ($p + [$gkey]), count: $x[$gkey]}
        else . end;
      if .f1 and .f2 then ., break $go else empty end)
    ) as $dict
  | if $dict | .f1 and .f2
    then setpath( $dict.f1.path; $dict.f2.count) 
    |    setpath( $dict.f2.path; $dict.f1.count)
    else . end ;

.food.fruit |= swap("apple"; "banana"; "type"; "count")

关于json - 链接 JQ if : if A then B C else D end,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/66260639/

相关文章:

json - 找不到为 laravel windows 执行 gulp 的模块

javascript - 从外部源解析 JSON

bash - 如何通过golang获取环境变量PS1?

linux - 从 bash 解析信息

bash - 在 bash 中解析和存储 curl 命令的 json 输出

json - 需要从包含特定字符 '/' 的 JSON 中获取所有键值对

javascript - 组合 JSON 数组

json - Bittrex API - Swift 中的 JSON 结构

BASH SHELL IF ELSE 在后台运行命令

json - jq - 合并两个 JSON 文件时出错 "cannot be multiplied"