从JQ中的稀疏对象数组生成新数组

时间:2019-03-16 16:12:02

标签: jq

我有一个要使用JQ处理的JSON文件。它在另一个对象中有一个对象数组,并带有一个我想用来填充新数组的键。

在我的实际用例中,它与许多其他绒毛嵌套在一起,并且有很多数组,但可以将其作为这种事情的简单但有代表性的示例:

{
  "numbers": [
    {
      "numeral": 1,
      "ordinal": "1st",
      "word": "One"
    },
    {
      "numeral": 2,
      "ordinal": "2nd",
      "word": "Two"
    },
    {
      "numeral": 5,
      "ordinal": "5th",
      "word": "Five"
    },
    {
      "some-other-fluff-i-want-to-ignore": true
    }
  ]
}

我想使用JQ获得基于元素的新数组,而忽略某些元素并处理丢失的元素。例如

[
  "The 1st word is One",
  "The 2nd word is Two",
  "Wot no number 3?",
  "Wot no number 4?",
  "The 5th word is Five"
]

针对存在的元素循环执行此操作非常简单,简洁且优雅:

.numbers | map( . | select( .numeral) | [ "The", .ordinal, "word is", .word ] | join (" "))

但是我找不到解决丢失条目的方法。我有一些可以正常工作的代码:

.numbers | [
  ( .[] | select(.numeral == 1) | ( [ "The", .ordinal, "word is", .word ] | join (" ")) ) // "Wot no number 1?",
  ( .[] | select(.numeral == 2) | ( [ "The", .ordinal, "word is", .word ] | join (" ")) ) // "Wot no number 2?",
  ( .[] | select(.numeral == 3) | ( [ "The", .ordinal, "word is", .word ] | join (" ")) ) // "Wot no number 3?",
  ( .[] | select(.numeral == 4) | ( [ "The", .ordinal, "word is", .word ] | join (" ")) ) // "Wot no number 4?",
  ( .[] | select(.numeral == 5) | ( [ "The", .ordinal, "word is", .word ] | join (" ")) ) // "Wot no number 5?"
]

它会按照以下方式产生可用的输出:

richard@sophia:~$ jq -f make-array.jq < numbers.json
[
  "The 1st word is One",
  "The 2nd word is Two",
  "Wot no number 3?",
  "Wot no number 4?",
  "The 5th word is Five"
]
richard@sophia:~$ 

但是,尽管它产生输出,处理丢失的元素并忽略了我不需要的位,但显然是极其naff的代码会为for循环或类似的操作而哭泣,但是我看不到JQ为此。有什么想法吗?

2 个答案:

答案 0 :(得分:2)

jq 解决方案:

jq 'def print(o): "The \(o.ordinal) word is \(o.word)";
    .numbers | (reduce map(select(.numeral))[] as $o ({}; .["\($o.numeral)"] = $o)) as $o
    | [range(0; ($o | [keys[] | tonumber] | max)) 
       | "\(.+1)" as $i
       | if ($o[$i]) then print($o[$i]) else "Wot no number \($i)?" end
    ]' input.json

输出:

[
  "The 1st word is One",
  "The 2nd word is Two",
  "Wot no number 3?",
  "Wot no number 4?",
  "The 5th word is Five"
]

答案 1 :(得分:1)

另一种解决方案!

jq  '[ 
       range(1; ( .numbers | max_by(.numeral)|.numeral ) +1 ) as $range_do_diplay  | 
       .numbers as $thedata | $range_do_diplay |
       . as $i | 
            if ([$thedata[]|contains( { numeral: $i })]|any ) 
            then 
               ($thedata|map(select( .numeral == $i )))|.[0]| "The \(.ordinal) word is \(.word) " 
            else 
               "Wot no number \($i)?" 
            end  
     ] ' numbers.json

此解决方案使用

  • max_by 查找数字
  • 的最大值
  • 范围以生成值列表
  • 使用变量存储中间值