I just started to learn Erlang, and really like their list comprehension syntax, for example:
Weather = [{toronto, rain}, {montreal, storms}, {london, fog}, {paris, sun}, {boston, fog}, {vancounver, snow}].
FoggyPlaces = [X || {X, fog} <- Weather].
In this case, FoggyPlaces
will evaluate to "london" and "boston".
What's the best way to do this in Ruby?
For example, an Array like (very common, I believe):
weather = [{city: 'toronto', weather: :rain}, {city: 'montreal', weather: :storms}, {city: 'london', weather: :fog}, {city: 'paris', weather: :sun}, {city: 'boston', weather: :fog}, {city: 'vancounver', weather: :snow}]
The best I got 'til now is:
weather.collect {|w| w[:city] if w[:weather] == :fog }.compact
But in this case, I have to call compact
to remove nil
values, and the example itself is not that readable as Erlang.
And even more, in the Erlang example, both city
and weather
are atoms. I don't even know how to get something that makes sense and looks good like this in Ruby.
First off, your data structures aren't equivalent. The equivalent Ruby data structure to your Erlang example would be more like
weather = [[:toronto, :rain], [:montreal, :storms], [:london, :fog],
[:paris, :sun], [:boston, :fog], [:vancouver, :snow]]
Secondly, yes, Ruby doesn't have list comprehensions nor pattern matching. So, the example will probably be more complex. Your list comprehension first filters all foggy cities, then projects the name. Let's do the same in Ruby:
weather.select {|_, weather| weather == :fog }.map(&:first)
# => [:london, :boston]
However, Ruby is centered around objects, but you are using abstract data types. With a more object-oriented data abstraction, the code would probably look more like
weather.select(&:foggy?).map(&:city)
which isn't too bad, is it?
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With