1

I have, for complicated reasons involving a trip from an Apple plist through xml2json, a number of JSON files with data in this form:

{ 
  "key": [ "key1", "key2", "key3" ],
  "string": [ "value1", "value2", "value3" ]
}

And I would like to convert that to a normal JSON object:

{ 
  "key1": "value1",
  "key2": "value2",
  "key3": "value3"     
}

After some head-banging, I came up with this jq program to do the trick:

jq '. as $d|[range(.key|length)|{"key":$d.key[.],"value":$d.string[.]}]|from_entries'

That works, but it seems a little convoluted. I was wondering if there were a cleaner solution?

This is indeed similar to this question, but the difference is that this is an object with named key and value elements instead just an array containing the two arrays directly.

2
  • Possible duplicate of Create object from array of keys and values Commented Dec 10, 2015 at 22:03
  • The linked question has the same idea, but in your case, you have an object of keys and values, rather than an array of keys and values. Commented Dec 10, 2015 at 22:04

2 Answers 2

4

The script you provide is already pretty good! This variation of your script saves the index into the variable instead of the input object, which feels more natural to read for me. It then creates an array of one key objects and adds them together.

jq '[range(.key | length) as $i | {(.key[$i]): .string[$i]}] | add'

When I first looked at this issue, I though that a zip builtin would improve the situation. Then I remembered: there is already a zip builtin! It's just called transpose. Using it, you can create a script such as this:

jq '[.key, .string] | transpose | map({key: .[0], value: .[1]}) | from_entries'

It seems easier to follow to me as well, although it is quite long too; I assume, however, that the focus is readability and not character count. Of course, you can also mix up both solutions:

jq '[.key, .string] | transpose | map({(.[0]): .[1]}) | add'
Sign up to request clarification or add additional context in comments.

Comments

0

Here is a solution which uses reduce with a state object holding an iteration index and a result object. It iterates over .key setting corresponding values in the result from .string

  .string as $v
| reduce .key[] as $k (
   {idx:0, result:{}}; .result[$k] = $v[.idx] | .idx += 1
  )
| .result

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.