jq
jq copied to clipboard
Docs: unclear explanation of `map_values()`
I love jq. Thank you.
I read the section of the Manual on map() and map_values(), and although I eventually believe I understand it, I found it hard to grasp the meaning of the text and only understood once I saw the example. I would like to propose a change to improve the text, but I don't want to do that until I better understand what you folks had had in mind when you wrote the text.
If you'd rather I merely propose a change in a PR, please comment saying so and I'll do it.
This is the text that confused me:
Similarly, map_values(x) will run that filter for each element, but it will return an object when an object is passed.
I think this means the following. Please tell me if I have it right or wrong.
- if
xis not an object, thenmap_values()behaves exactly likemap(). - if
xis an object, thenmap_values()transforms only the values exactly likemap()would, but then returns an object with the same keys and the new values.
Of course, those explanations are also terrible, but it's the best I can draft at this moment while my brain wants to get back to my current task. :)
Questions:
- How well do I understand was
map_values()does? - Is this what you meant to say by "...but it will return an object when an object is passed"? (I think so, but I'd like to clarify.)
- Instead of answering this second question, would you prefer that I just submit a PR after I've written that text in a much nicer way? ;)
Hey, I think you have understood it correctly. If your curious you can check builtin.jq for how it's implemented def map_values(f): .[] |= f; (map is def map(f): [.[] | f];). And if your really curious you can check _modify which is what |= gets rewritten to.
I suggest you make a PR and I like how you listed the cases. But it might take some time until it gets merged, the people with merge rights works a bit sporadically.
Hej! Tusentack. Det var inte i går!
Thanks. I will keep my expectations quite reasonable. :+1:
Det samma! hoppas allt är bra :)
You can read in #2305 about the status of jq, i really hope something can be sorted out.
map/1 accepts arrays and objects as inputs but always produces an array because it's defined like this: def map(f): [.[] | f];.
map_values/1 accepts arrays and objects as inputs and produces the same kind of value.
So if you want to map over the values of an object but keep it an object, then you should use map_values.
I think of jq's map/1 as similar to flat map functions in other languages, you can use it to map a single value to zero, one or more values.
[ 10, 20, 30 ] |
map(. + (-1, 0, 1))
# [9,10,11,19,20,21,29,30,31]
[ 1, 1, 1, 2, 4, 5, 8, 1 ] |
map(if . % 2 == 0 then ., "hi" else . + 1 end)
# [2,2,2,2,"hi",4,"hi",6,8,"hi",2]
I almost never use map_values/1, use .[] |= when I want to map a value to another value.
A reason why I prefer using map/1 for arrays even if .[] |= or map_values() could work is that in jq 1.6, if you use something that uses labels, try, foreach, ? or similar things (even indirectly e.g. using first/1 or a function that uses try somewhere) as RHS for |= (even indirectly passing it to map_values/1), it breaks.
Using map/1 you avoid those problems because its implementation doesn't use |=.
[ range(10) | tostring ] | .[] |= try tonumber catch []
# jq 1.6: [[],[],[],[],[],[],[],[],[],[]]
# expected: [0,1,2,3,4,5,6,7,8,9]
[ range(10) | tostring ] | map(try tonumber catch [])
# jq 1.6: [0,1,2,3,4,5,6,7,8,9]
# expected: [0,1,2,3,4,5,6,7,8,9]
Note that this bug has been fixed on master
I almost never use map_values/1, use .[] |= when I want to map a value to another value.
Me too. And I almost never use map -- map(f) is just a one-character savings over [.[]|f]! :)
Fixed by #2680