在jq中“转置”对象

时间:2015-09-02 15:28:27

标签: json transpose relation jq

我不确定“transpose”在这里是否是正确的术语,但我希望使用jq来转置这样的二维对象:

[
    {
        "name": "A",
        "keys": ["k1", "k2", "k3"]
    },
    {
        "name": "B",
        "keys": ["k2", "k3", "k4"]
    }
]

我想将其转换为:

{
    "k1": ["A"],
    "k2": ["A", "B"],
    "k3": ["A", "B"],
    "k4": ["A"],
}

我可以使用.[] | {key: .keys[], name}拆分对象以获取密钥和名称列表,或者我可以使用.[] | {(.keys[]): [.name]}来获取键值对{"k1": ["A"]}的集合,依此类推,但我不确定这两种方法的最终连接步骤。

这些方法中的任何一个都朝着正确的方向发展吗?还有更好的方法吗?

3 个答案:

答案 0 :(得分:5)

这应该有效:

map({ name, key: .keys[] })
    | group_by(.key)
    | map({ key: .[0].key, value: map(.name) })
    | from_entries

基本方法是将每个对象转换为名称/密钥对,按密钥重新组合,然后将它们映射到对象的条目。

这会产生以下输出:

{
  "k1": [ "A" ],
  "k2": [ "A", "B" ],
  "k3": [ "A", "B" ],
  "k4": [ "B" ]
}

答案 1 :(得分:1)

这是一个简单的解决方案,也可能更容易理解。它基于这样的想法:可以通过添加有关其他(键 - >值)对的详细信息来扩展字典(JSON对象):

# input: a dictionary to be extended by key -> value 
# for each key in keys
def extend_dictionary(keys; value):
  reduce keys[] as $key (.; .[$key] += [value]);

reduce .[] as $o ({}; extend_dictionary($o.keys; $o.name) )


$ jq -c -f transpose-object.jq input.json
{"k1":["A"],"k2":["A","B"],"k3":["A","B"],"k4":["B"]}

答案 2 :(得分:0)

对于“名称”的所有值的情况,这是一个更好的解决方案 是不同的。它更好,因为它使用完全通用的 filter,invertMapping;也就是说,invertMapping可以是内置的或 库函数。借助此功能,解决方案 变成一个简单的三线。

此外,如果“name”的值并非都是唯一的,那么解决方案 通过修改输入的初始减少,可以很容易地调整下面的内容 (即在调用invertMapping之前的行)。

# input: a JSON object of (key, values) pairs, in which "values" is an array of strings; 
# output: a JSON object representing the inverse relation
def invertMapping: 
  reduce to_entries[] as $pair
    ({}; reduce $pair.value[] as $v (.; .[$v] += [$pair.key] ));


map( { (.name) : .keys} )
| add
| invertMapping