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

3

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

{
    "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"
  }
]
4个回答

1

我更喜欢使用不同类型的过滤器与交替来使其更加紧凑。假设您只需处理数组或标量的值,我会以这种方式编写:

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

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

不要低估可以生成多个值的表达式的实用性,有效使用时可以使您的过滤器变得更简单。

哇!简短而整洁。 - Jerry Thomas

1
我能够使用以下方法解决这个问题:
  • 将项目转换为键值对
  • 将值转换为数组并展平
  • 映射每个项目
    • 将类型存储在变量中
    • 映射数组中的每个值,添加类型属性
    • 展平嵌套数组
to_entries 
  | map_values({value:[.value]|flatten, type:.key}) 
  | map( .type as $type | .value | map({type:$type, value: .}))
  |flatten

{{链接1:jqplay}}


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

太棒了。谢谢,我看到这甚至在值为对象时也起作用。 - Jerry Thomas
是的,这就是 jq 的目标——通用而不复杂! - peak

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

jq "$(cat d.jq)" d.json" 应该改为 jq -f d.jq d.json - peak
谢谢。如果我去掉 |strings,它也可以适用于对象。 - Jerry Thomas

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接