【问题标题】:How do I convert a named list to an array of objects如何将命名列表转换为对象数组
【发布时间】:2019-07-16 09:25:08
【问题描述】:

我有一些看起来像这样的数据

{
    "type1": [
      "a", "b"
    ],
    "type2": [
      "c", "d"
    ],
    "type3": "x"
}

我想把它转换成

[
    {"value": "a", "type": "type1" },
    {"value": "b", "type": "type1" },
    {"value": "c", "type": "type2" },
    {"value": "d", "type": "type2" },
    {"value": "x", "type": "type3" },
]

数组元素可以有一个或多个值。这可能使用jq吗?

我能够处理非数组元素,但我的表达式只保留列表中的最后一项。

to_entries 
  | map_values({value:[.value]|flatten, type:.key})
  | map_values({value:.value[], type:.type})

我得到这个结果,其中元素“b”和“d”被排除在结果之外。

[
  {
    "value": "a",
    "type": "type1"
  },
  {
    "value": "c",
    "type": "type2"
  },
  {
    "value": "x",
    "type": "type3"
  }
]

【问题讨论】:

    标签: arrays json iteration jq


    【解决方案1】:

    我更喜欢交替使用各种类型的过滤器以使其更紧凑。假设您只需要处理数组或标量的值,我会这样写:

    [to_entries[] | {value:(.value | arrays[] // .), type:.key}]
    

    https://jqplay.org/s/1jCG6soXuG

    不要低估可以生成多个值的表达式的用处,它可以让您的过滤器在有效使用时变得不那么复杂。

    【讨论】:

    • 哇!短而整洁。
    【解决方案2】:

    我可以使用以下方法解决这个问题

    • 将项目转换为键值对
    • 将值转换为数组并展平
    • 映射每个项目
      • 在变量中存储类型
      • 映射数组中的每个值,添加类型属性
      • 扁平化嵌套数组
    to_entries 
      | map_values({value:[.value]|flatten, type:.key}) 
      | map( .type as $type | .value | map({type:$type, value: .}))
      |flatten
    

    jqplay

    【讨论】:

      【解决方案3】:

      这是一个高效、简洁且可能是“规范”的解决方案:

      [to_entries[]
       | (if .value|type == "array" then {value: .value[]} else {value} end)
         + {type: .key} ]
      

      或者等效地,如果您更喜欢使用map:

      to_entries
      | map( (if .value|type == "array" then {value: .value[]} 
              else {value}
              end)
            + {type: .key} )
      

      这里的微妙之处在于 {value: .value[]} 扩展为 JSON 对象流,就像是:.value[] | {value: .}

      【讨论】:

      • 太棒了。谢谢,我发现即使值是对象也可以使用。
      • 是的,这就是 jq 的重点 - 通用性没有复杂性!
      【解决方案4】:

      我把你的数据放在 d.json 里,然后把这个放在 d.jq 里:

      # vim: tabstop=2 expandtab shiftwidth=2 softtabstop=2
      [ 
        .
        |to_entries[]
        |.key as $k
        |(
          (.value|strings|{"type":($k),"value":.}),
          (.value|arrays|reduce .[] as $i ( [];  . += [ { "type": ($k), "value":  $i } ] ) )[]
        )
      ]
      

      然后用 jq 运行

      jq -f d.jq d.json
      

      我知道一定有更好的方法 :-) 但你最终会得到:

      [
        {
          "type": "type1",
          "value": "a"
        },
        {
          "type": "type1",
          "value": "b"
        },
        {
          "type": "type2",
          "value": "c"
        },
        {
          "type": "type2",
          "value": "d"
        },
        {
          "type": "type3",
          "value": "x"
        }
      ]
      

      【讨论】:

      • jq "$(cat d.jq)" d.json 应改为jq -f d.jq d.json。
      • 谢谢。如果我删除 |strings 它也适用于对象。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-04-11
      • 2017-06-20
      相关资源
      最近更新 更多