caarlos0 caarlos0 - 1 year ago 72
Ruby Question

Erlang vs Ruby list comprehensions

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,
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
to remove
values, and the example itself is not that readable as Erlang.

And even more, in the Erlang example, both
are atoms. I don't even know how to get something that makes sense and looks good like this in Ruby.

Answer Source

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| 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

which isn't too bad, is it?