首页 > 解决方案 > 为什么jq中的“减少”不减少

问题描述

tl;博士

在 的语言中jq,为什么是

$ jq --compact-output reduce (1,2,3,4) as $i ([]; . + [$i])
[1,2,3,4]

不一样

$ jq --compact-output (1,2,3,4) | reduce . as $i ([]; . + [$i])
[1]
[2]
[3]
[4]

完整的问题和讨论

我有一个理论上的问题,因为我已经找到了一种方法来获得我想要的转换,但我仍然不完全理解为什么我的第一次尝试失败了,我想要一个解释。

jqPlay上的交互式示例

我有输入

{
  "data": {
    "k1": "v1"
  },
  "item": {
    "data": {
      "k2": "v2"
    }
  }, 
  "list": {
    "item": {
      "data": {
        "k3": "v3",
        "k4": "v4"
      }
    }
  }
}

我想将作为“数据”键的直接子级的所有键的所有值收集到一个数组中。所以我想要的输出是

["v1","v2","v3","v4"]

我最终发现这行得通

jq --compact-output '[.. | .data? | select(.) | to_entries | .[].value]'

我的问题是,为什么我不能让它工作reduce?我最初尝试过

.. | .data? | select(.) | to_entries | .[].value | reduce . as $v ([]; . + [$v])

但这给了我

["v1"]
["v2"]
["v3"]
["v4"]

反而。我的问题是为什么?reduce应该迭代多个值,但它迭代了什么样的多个值,什么样的值被视为单独reduce语句的单独输入?

我想我的基本困惑是.(点)什么时候是一个有 4 个结果的表达式,什么时候是 4 个表达式?或者如果.总是一个有 1 个结果的表达式,你如何将 4 个结果收集回 1,这就是reduce全部内容?数组运算符是唯一的方法吗?

标签: jq

解决方案


形式的表达:

reduce STREAM as ...

减少给定的流,而复合表达式:

STREAM | reduce . as ...

为流中的每个项目调用reduce一次,并且对于每个调用,.都是该项目。


如果在这种情况下流的概念不清楚,您可能有兴趣阅读我写的面向流的 jq 介绍: https ://github.com/pkoppstein/jq/wiki/A-Stream-orientation-Introduction- to-jq


推荐阅读