【问题标题】:How to select items in JQ based on value in array如何根据数组中的值选择JQ中的项目
【发布时间】:2014-09-03 17:05:20
【问题描述】:

我有一个这样的文件:

{"items":["blue","green"]}
{"items":["yellow","green"]}
{"items":["blue","pink"]}

如何使用jq 选择并仅显示“items”数组中包含“blue”的 JSON 值?

所以输出将是:

{"items":["blue","green"]}
{"items":["blue","pink"]}

【问题讨论】:

    标签: json jq


    【解决方案1】:

    找到答案

    jq 'select(.items | index("blue"))'
    

    【讨论】:

    • 这是迄今为止我发现的最好的解决方案,用于处理具有单个列表项作为字符串且不可迭代的数据。请注意,这不是完全匹配。
    【解决方案2】:

    2017 年 1 月 30 日,添加了一个名为 IN 的内置函数,用于有效测试 JSON 实体是否包含在流中。它还可以用于有效地测试数组中的成员资格。在本例中,相关用法为:

    select( .items as $items | "blue" | IN($items[]) )
    

    如果你的 jq 没有IN/1,那么只要你的 jq 有first/1,你就可以使用这个等价的定义:

    def IN(s): . as $in | first(if (s == $in) then true else empty end) // false;
    

    任何/0

    在这里使用any/0 效率相对较低,例如与使用any/1相比:

    select( any( .items[]; . == "blue" ))
    

    (实际上,index/1 通常足够快,但目前(jq 1.5 和至少到 2017 年 7 月的版本)的实现并不理想。)

    【讨论】:

      【解决方案3】:

      虽然您所拥有的确实有效,但使用contains 会更正确。我会避免这种使用,因为它会导致混乱。 index("blue")0,人们不会认为这是一个真实的值,可能会期望它被排除在结果之外。

      考虑改用这个过滤器:

      select(.items | contains(["blue"]))
      

      如果您想要多个匹配项,只需向数组中添加更多内容,它就有额外的好处。

      正如 Will 在 cmets 中指出的那样,这并不完全正确。此处使用子字符串匹配(contains 递归使用)比较字符串。

      回想起来,contains 并没有像我想象的那样成功。使用index 有效,但我个人不会使用它。通过查找对我来说感觉不对的索引来确定一个项目是否在集合中。使用contains 对我来说更有意义,但鉴于这些信息,在这种情况下它并不理想。


      这是一个应该可以正常工作的替代方法:

      select([.items[] == "blue"] | any)
      

      或者,如果您希望能够匹配更多值,则可以采用更具可扩展性的方式:

      select(.items as $values | ["blue", "yellow"] | map([$values[] == .] | any) | all)
      

      【讨论】:

      • 这个答案不正确。尽管在某些情况下它会(危险地)起作用,但它也可能导致误报。 “包含”严格来说是子字符串搜索。反例:jq -n '["foobar","bar","baz"] | contains(["foo"])' 结果为真。比较:jq -n '["foobar","bar","baz"] | (index("foo")==null|not)' 正确导致错误。
      • 感谢您指出 Will,我没有意识到它为数组递归地运行过滤器。我确信有一种方法可以做到这一点,同时仍然具有可扩展性。
      • 我不知道这是否可以扩展,因为我怀疑在所有情况下都会执行迭代搜索,但我之前也使用过:jq -n '["foobar","bar","baz"] | [.[] | select( . == "foobar" )] | length > 0' 至少有 潜在并行运行搜索。
      【解决方案4】:

      我需要对对象的相同情况使用“正则表达式”。 (当然,在另一种情况下)。我编写代码是因为我没有在这些页面中找到满足我需求的解决方案。这可能对某人有用。

      例如,使用正则表达式匹配蓝色:

      jq 'select(.items[]|test("bl.*"))' yourfile.json
      

      jqPlay

      【讨论】:

        猜你喜欢
        • 2017-11-26
        • 1970-01-01
        • 2021-08-03
        • 2017-12-12
        • 2016-09-30
        • 2015-01-23
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多