/Users/leeyi/project/imboy.pub/imboy >
erl
Erlang/OTP 25 [erts-13.2.2.4] [source] [64-bit] [smp:8:8] [ds:8:8:10] [async-threads:1] [jit:ns] [dtrace]
Eshell V13.2.2.4 (abort with ^G)
1> Weather = #{toronto => rain, montreal => storms, london => fog, paris => sun, boston => fog, vancouver => snow}.
#{boston => fog,london => fog,montreal => storms,paris => sun,
toronto => rain,vancouver => snow}
2>
2>
2> Weather.
#{boston => fog,london => fog,montreal => storms,paris => sun,
toronto => rain,vancouver => snow}
3> FoggyPlaces = [X || X := fog <- Weather].
* 1:23: syntax error before: ':='
3> [X || X => fog <- Weather].
* 1:9: syntax error before: '=>'
The comprehension which you used would work with a list:
WeatherList = [{toronto, rain}, {montreal, storms}, {london, fog}, {paris, sun}, {boston, fog}, {vancouver, snow}].
7> [X || X={_, fog} ← WeatherList].
[{london,fog},{boston,fog}]
But as your data is in a map, you must use map comprehension syntax, like this:
#{City => fog || City := fog ← Weather}.
I think map comprehensions were introduced with 26:
Correct
Yup, the article you took this example says
The same kind of stuff can be done with map comprehensions, once they’re made available
And map comprehensions were only introduced in OTP-26 (while maps were introduced much earlier - in OTP-17)
Thank you for reminding me!
I didn’t read carefully enough to notice “once they’re made available.”
Available in Erlang/OTP 26
erl
Erlang/OTP 26 [erts-14.2.1] [source] [64-bit] [smp:8:8] [ds:8:8:10] [async-threads:1] [jit] [dtrace]
Eshell V14.2.1 (press Ctrl+G to abort, type help(). for help)
1> Weather = #{toronto => rain, montreal => storms, london => fog, paris => sun, boston => fog, vancouver => snow}.
#{toronto => rain,montreal => storms,london => fog,
paris => sun,boston => fog,vancouver => snow}
2> FoggyPlaces = [X || X := fog <- Weather].
[london,boston]
That is a list comprehension using a map generator
That said, all of this should work (in OTP 26):
1> [ {X} || X <- [1, 2, 3] ].
[{1}, {2}, {3}]
2> [ {X} || <<X>> <= <<4, 5, 6>> ].
[{4}, {5}, {6}]
3> [ {X, Y} || X := Y #{7 => 8, 9 => 10, 11 => 12} ].
[{7, 8}, {9, 10}, {11, 12}]
4> << <<(X*X)>> || X <- [1, 2, 3] >>.
<<1, 4, 9>>
5> << <<(X*X)>> || <<X>> <- <<4, 5, 6>> >>.
<<16, 25, 36>>.
6> << <<(X*Y)>> || X := Y <- #{7 => 8, 9 => 10, 11 => 12} >>.
<<56, 90, 132>>
7> #{ X => foo || X <- [1, 2, 3] }.
#{1 => foo, 2 => foo, 3 => foo}
8> #{ X => bar || <<X>> <= <<4, 5, 6>> }.
#{4 => bar, 5 => bar, 6 => bar}
9> #{ Y => X || X := Y <- #{7 => 8, 9 => 10, 11 => 12} }.
#{8 => 7, 10 => 9, 12 => 11}
List and especially binary comprehensions with a map generator are of limited use, however, since there is no defined order. For example, the list resulting from [{X, Y} || X := Y <- #{1 => 2, 3 => 4}]
could be either [{1, 2}, {3, 4}]
or [{3, 4}, {1, 2}]
.
And this is the reason why in OTP-26 they added “ordered map iterators” and map generators support map iterators as input:
> Map => #{1 => a, 2 => b}.
> [{K, V} || K := V <- maps:iterator(Map, ordered)].
[{1, a}, {2, b}]
> [{K, V} || K := V <- maps:iterator(Map, reversed)].
[{2, b}, {1, a}]