Map Iteration
In Ruby at least, maps can be iterated over using each {|key, value| ..} — this is very easy and intuitive. I thought if one value was specified it would be the key, and two would be key and value, the magic happening in each:
put &a=1 &b=2 | each {|k| echo $k }
put &a=1 &b=2 | each {|k v| echo $k"="$v }
But there are more types of syntax for iteration. I was searching on previous proposals for iteration of maps and found #1243 which is supposed to be about strings but thanks to @krader1961 expanded to discuss iterating maps. @hanche thought of more options to iterate over maps:
@krader1961 You're doing great at being devil's advocate! At the opposite end of the available options, I've been thinking a bit about maps and how to iterate them. I was wondering above whether iterating a map should yield just the keys, or key-value pairs. So I had an idea: Why not both? So here we go, then:
Assuming
$mapholds a map, we could let$@mapexpand to the keys, and (wait for it)$@@mapexpand to key-value pairs.
What about
all? Well, since we already havekeysto extract the keys, we could letall $mapproduce key-value maps. I know, that makes for a bit of inconsistency, since ideally,(all $map)should be equivalent to$@map. But, I am brainstorming here. Maybe someone can think of a better way.
And finally, we could extend the
forsyntax, allowing bothfor key $map { … }andfor key value $map { … }. The latter, being syntactically different, can't be confused with the single-variable version offor.
A totally different option would be to let iteration of a map always return key-value pairs, and then using destructuring, we could write the above examples as
for [key _] $map { … }andfor [key value] $map { … }. This allows for greater consistency, perhaps. Then$@mapwould return key-value pairs, as wouldall $map. Come to think of it, then we could get the keys by$@map[0].
Originally posted by @hanche in https://github.com/elves/elvish/issues/1243#issuecomment-780381048
Destructuring is a generally useful feature, so I prefer using it for iterating maps. Something like:
var m = [&k=v &k2=v2]
pairs $m
# ▶ [k v]
# ▶ [k2 v2]
pairs $m | each {|[k v]| ... }
# ...
It's slightly awkward to use in a for loop:
for [k v] [(pairs $m)] { ... }
But maybe for can special-case maps:
for [k v] $m { ... }
Pattern matching / destructuring in general has a tracking issue #217. For map iteration specifically we need:
- A
pairscommand that outputs[k v]pairs of a map - Destructuring a list with a known number of elements
- Maybe: special-casing maps in the
forloop