如何将命名列表转换为对象数组

时间:2019-07-16 09:25:08

标签: arrays json iteration jq

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

{
    "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"
  }
]

5 个答案:

答案 0 :(得分:1)

我能够使用以下方法解决此问题

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

jqplay

答案 1 :(得分:1)

这是一种高效,简洁,也许是“规范的”解决方案:

[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: .}

答案 2 :(得分:1)

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

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

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

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

答案 3 :(得分:0)

我将您的数据放入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"
  }
]

答案 4 :(得分:0)

类似,使用基于步行路径的Unix工具 jtc 可以执行相同的JSON操作:

bash $ <typevalue.json jtc -w'[:]<L>k<V>a:' -T'{"value":{{V}},"type":{{L}}}' -j
[
   {
      "type": "type1",
      "value": "a"
   },
   {
      "type": "type1",
      "value": "b"
   },
   {
      "type": "type2",
      "value": "c"
   },
...
  • 在行走(-w)每个顶部记录([:])时,其标签将保留在命名空间L<L>k)中,然后保留在同时记录(<V>a:中的记录(V
  • 在打印行走元素之前,对结果进行具有所需结构的模板插值(-T)(从命名空间保留值VL插值)
  • -j将行走的元素包装回JSON数组

PS>披露:我是jtc-用于JSON操作的shell cli工具的创建者