【问题标题】:JQ sorting key by arbitrary orderJQ 按任意顺序排序键
【发布时间】:2018-03-29 12:46:23
【问题描述】:

我正在尝试以任意格式按键排序(键“事件”应该是第一个)

我知道这是按字母顺序对键进行排序的: jq -S '.'文件.json

但是有没有对键进行排序的功能,以便第一个总是相同的,而不是按字母顺序?

这是为了让它们更易于阅读,并首先拥有最重要的密钥

目前有: {key1:value, shouldbeFirstKey:value2, ...} 想 {shouldbeFirstKey:value2, key1:value, ...}

【问题讨论】:

    标签: json sorting key jq


    【解决方案1】:

    @jq170727 回答的想法:

    jq '
    def reorder(a; n):
        def order(a; n):
            a as $a |
            n as $n |
            index($a) as $i |
            if $i == null then .
            else
                if $i<$n then .[:$i] + .[$i+1:$n+1] + [$a] + .[$n+1:]
                elif $n<$i then .[:$n] + [$a] + .[$n:]
                else .
                end
            end;
    
        . as $in
      | if type == "object" then
          reduce (keys_unsorted|order(a;n))[] as $key(
            {}; . + { ($key):  ($in[$key] | reorder(a; n)) }
          )
        elif type == "array" then map( reorder(a; n) )
        else .
        end;
    
    [.[]  | reorder("id"; 0)| reorder("size"; 3) | reorder("name"; 1)]'
    data.json
    
    

    【讨论】:

      【解决方案2】:

      假设我们有一个带有一堆键的对象,并希望其中一些键以特定顺序出现,而其他键保持原样。然后可以使用以下示例说明的技术:

      $ jq -n '{a:2,b:3,first:0,second:1} | . as $in | {first,second} + $in'
      

      结果:

      {
        "first": 0,
        "second": 1,
        "a": 2,
        "b": 3
      }
      

      重新生成密钥

      让我们将定义键顺序的对象称为“模板对象”(上面的{first,second})。请注意,使用上述技术,“模板对象”中的键始终出现在结果中。如果我们只希望模板对象键出现在输入中时出现在结果中,我们可以使用以下函数修改上述方法:

      def rekey(obj):
        . as $in
        | reduce (obj|keys_unsorted)[] as $k ({};
            if $in|has($k) then . + {($k): $in[$k]} else . end)
        | . + $in ;
      

      例如:

      {a:2,b:3,first:0,second:1} | rekey({first,second,third})
      

      产生:

      {
        "first": 0,
        "second": 1,
        "a": 2,
        "b": 3
      }
      

      walk/1

      如果想要递归地重新排序键,可以使用walk/1(定义为https://github.com/stedolan/jq/blob/master/src/builtin.jq), 如此处所示,使用上述rekey 的定义:

      walk(if type == "object" then rekey($template) else . end)
      

      其中 $template 代表“模板对象”。

      无需定义walk/1 的特殊变体。只需定义一个函数,该函数将任意对象作为输入,并产生所需的重新排序。

      (如果你的jq自带的walk/1版本使用keys,那么你应该考虑更新你的jq,或者重新定义walk/1使用keys_unsorted。)

      【讨论】:

        【解决方案3】:

        这是一个过滤器(源自walk/1 [source]),它将使用函数重新排序子对象的键:

        def reorder(order):
            . as $in
          | if type == "object" then
              reduce (keys_unsorted|order)[] as $key(
                {}; . + { ($key):  ($in[$key] | reorder(order)) }
              )
            elif type == "array" then map( reorder(order) )
            else .
            end;
        

        order 函数应该以任何所需的顺序返回键集。例如以下函数将“shouldbeFirstKey”移动到第一个位置

        def neworder:
            "shouldbeFirstKey" as $s
          | index($s) as $i
          | if $i==null then . else [$s] + .[:$i] + .[$i+1:] end
        ;    
        

        这样

          {key1:"value", shouldbeFirstKey:"value2", other:{key3:"value3", shouldbeFirstKey:"value4"}}
        | reorder(neworder)
        

        产生输出

        {
          "shouldbeFirstKey": "value2",
          "key1": "value",
          "other": {
            "shouldbeFirstKey": "value4",
            "key3": "value3"
          }
        }
        

        Try it online!

        【讨论】:

        • 一个更清晰、更高效的 neworder 版本是: def neworder: "shouldbeFirstKey" as $s |索引($s) 作为 $i |如果 $i==null 那么 .否则 [$s] + .[:$i] + .[$i+1:] end ;
        • 我已经用peak's 替换了我的neworder 版本。如果有多个键需要重新排序,那么可能会有比这个更好的答案。 Also just using walk/1 as shown in the manual jq 'walk(if type == "array" then sort else . end)' for type "object" with an appropriate choice of sort might be simpler still.
        • 感谢更新,只是为了明白,我应该在哪里定义函数def neworder?我刚开始使用 jq,我想从命令行运行它。干杯
        • 我会将定义和对reorder(neworder) 的调用放在一个文件中(例如filter.jq)并使用-f 选项。例如。 jq -M -f filter.jq data.json.
        • neworder函数应该调用reorder函数吗?我错过了什么吗?我把这两个函数放在 filter.jq
        猜你喜欢
        • 2020-07-08
        • 1970-01-01
        • 2011-08-03
        • 2020-12-23
        • 1970-01-01
        • 2011-01-13
        • 1970-01-01
        • 2016-06-03
        • 2012-01-04
        相关资源
        最近更新 更多