代码之家  ›  专栏  ›  技术社区  ›  Logan Lee

通过在jq中一对一比较两个流进行过滤

  •  0
  • Logan Lee  · 技术社区  · 3 年前

    我有小溪

    {
        "key": "a",
        "value": 1
    }
    {
        "key": "b",
        "value": 1
    }
    {
        "key": "c",
        "value": 1
    }
    {
        "key": "d",
        "value": 1
    }
    {
        "key": "e",
        "value": 1
    }
    

     (true,true,false,false,true)
    

    我想比较一下两者 一对一 并且仅当相应的布尔值为 true .

    所以我想要输出

    {
        "key": "a",
        "value": 1
    }
    {
        "key": "b",
        "value": 1
    }
    {
        "key": "e",
        "value": 1
    }
    

    我试过了( https://jqplay.org/s/GGTHEfQ9s3 )

    filter:
    . as $input | foreach (true,true,false,false,true) as $dict ($input; select($dict))
    
    input:
    {
        "key": "a",
        "value": 1
    }
    {
        "key": "b",
        "value": 1
    }
    {
        "key": "c",
        "value": 1
    }
    {
        "key": "d",
        "value": 1
    }
    {
        "key": "e",
        "value": 1
    }
    

    但我得到了输出:

    {"key":"a","value":1}
    {"key":"a","value":1}
    null
    {"key":"b","value":1}
    {"key":"b","value":1}
    null
    {"key":"c","value":1}
    {"key":"c","value":1}
    null
    {"key":"d","value":1}
    {"key":"d","value":1}
    null
    {"key":"e","value":1}
    {"key":"e","value":1}
    null
    

    我们将不胜感激。

    1 回复  |  直到 3 年前
        1
  •  2
  •   pmf    3 年前

    一种方法是将流作为数组读入,使用 transpose 匹配他们的物品,以及 select 由一个输出,另一个输出:

    jq -s '[.,[(true,true,false,false,true)]] | transpose[] | select(.[1])[0]' objects.json
    

    Demo

    另一种方法是将流作为数组读取,将布尔数组转换为 indices 条件匹配的位置,并使用它们引用到对象数组中:

    jq -s '.[[(true,true,false,false,true)] | indices(true)[]]' objects.json
    

    Demo

    同样的方法,但使用 nth 参考 inputs 流需要更多的预防措施,因为连续消耗流输入需要提供相对距离,而不是绝对位置 N .可以通过连续检查下一个的位置来实现转换 true 价值使用 index 还有 while 循环:

    jq -n 'nth([true,true,false,false,true] | while(. != []; .[index(true) + 1:]) | index(true) | values; inputs)' objects.json
    

    Demo

    reduce 直接迭代布尔值 选择 任何适当的 input :

    jq -n 'reduce (true,true,false,false,true) as $dict ([]; . + [input | select($dict)]) | .[]' objects.json
    

    Demo

    使用 foreach 如你所愿,也需要 -n 不错过第一项的选项:

    jq -n 'foreach (true,true,false,false,true) as $dict (null; input | select($dict))' objects.json
    

    Demo

        2
  •  0
  •   peak    3 年前

    不幸的是,jq的每次调用目前最多只能处理一个外部JSON流。这通常不是一个问题,除非两个流都非常大,所以在这个答案中,我将重点介绍一个可扩展的解决方案。事实上,无论数据流有多大,所需的计算机内存量都是微乎其微的。

    为了简单起见,我们假设:

    • 魔鬼json是一个由json布尔值流(即,非逗号分隔)组成的文件;
    • 对象json是json对象的流;
    • 溪流的长度相同;
    • 我们在bash或类似bash的环境中工作。

    然后我们可以:

    paste -d '\t' demon.json <(jq -c . objects.json) | jq -n '
      foreach inputs as $boolean (null; input; select($boolean))'
    

    所以除了公司的启动成本 paste jq ,我们基本上只需要足够的内存来保存对象中的一个对象。每次使用json。这个解决方案也非常快。

    当然,如果你不喜欢。json已经是JSONL(json行)格式,那么就不需要第一次调用上面的jq了。