Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Docs: unclear explanation of map_values() #2466

Closed
jbrains opened this issue Aug 24, 2022 · 7 comments
Closed

Docs: unclear explanation of map_values() #2466

jbrains opened this issue Aug 24, 2022 · 7 comments
Labels

Comments

@jbrains
Copy link
Contributor

jbrains commented Aug 24, 2022

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 x is not an object, then map_values() behaves exactly like map().
  • if x is an object, then map_values() transforms only the values exactly like map() 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? ;)
@wader
Copy link
Member

wader commented Aug 24, 2022

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.

@jbrains
Copy link
Contributor Author

jbrains commented Aug 24, 2022

Hej! Tusentack. Det var inte i går!

Thanks. I will keep my expectations quite reasonable. 👍

@wader
Copy link
Member

wader commented Aug 24, 2022

Det samma! hoppas allt är bra :)

You can read in #2305 about the status of jq, i really hope something can be sorted out.

@nicowilliams
Copy link
Contributor

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.

@emanuele6
Copy link
Member

emanuele6 commented Jul 9, 2023

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

@nicowilliams
Copy link
Contributor

nicowilliams commented Jul 9, 2023

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]! :)

@emanuele6
Copy link
Member

Fixed by #2680

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants