Combine two JSON arrays in a single file using jq

Viewed 473

I have a JSON file with two arrays. I'd like to combine the arrays into a single array of objects, each of which contains an element from each of the original arrays.

JSON input looks like this:

{
  "en": [
    "E1",
    "E2",
    "E3",
    "E4"
  ],
  "fr": [
    "F1",
    "F2",
    "F3",
    "F4"
  ]
}

Desired output:

[
  { "en":"E1", "fr":"F1"},
  { "en":"E2", "fr":"F2"},
  { "en":"E3", "fr":"F3"},
  { "en":"E4", "fr":"F4"}
]

No matter what I try I can't tame jq into delivering this. The closest I have come is using the filter . | {en:.en[],fr:.fr[]} which gives me every possible pairing of the arrays as follows:

{
  "en": "E1",
  "fr": "F1"
}
{
  "en": "E1",
  "fr": "F2"
}
{
  "en": "E1",
  "fr": "F3"
}
{
  "en": "E1",
  "fr": "F4"
}
{
  "en": "E2",
  "fr": "F1"
}
{
  "en": "E2",
  "fr": "F2"
}
{
  "en": "E2",
  "fr": "F3"
}
{
  "en": "E2",
  "fr": "F4"
}
{
  "en": "E3",
  "fr": "F1"
}
{
  "en": "E3",
  "fr": "F2"
}
{
  "en": "E3",
  "fr": "F3"
}
{
  "en": "E3",
  "fr": "F4"
}
{
  "en": "E4",
  "fr": "F1"
}
{
  "en": "E4",
  "fr": "F2"
}
{
  "en": "E4",
  "fr": "F3"
}
{
  "en": "E4",
  "fr": "F4"
}

How can I get it to pair the first elements of each array, the second elements, etc.

3 Answers

You could also use transpose to "zip" the arrays together:

[[.en,.fr] | transpose[] | {en:.[0], fr:.[1]} ]

I used range() to iterate over the elements of the arrays:

jq '[range(.en|length) as $i | {en: .en[$i], fr: .fr[$i]}]' file.json

Here's a solution that will work with arbitrarily many keys and that does not require knowledge of the key names beforehand:

def objectify($keys):
  [$keys, .] | transpose | map({(.[0]): .[1]}) | add;

keys_unsorted as $keys
| [[.[]] | transpose[] | objectify($keys)]
Related