To do the equivalent of Python list comprehensions, I\'m doing the following:
some_array.select{|x| x % 2 == 0 }.collect{|x| x * 3}
Is ther
I've just published the comprehend gem to RubyGems, which lets you do this:
require 'comprehend'
some_array.comprehend{ |x| x * 3 if x % 2 == 0 }
It's written in C; the array is only traversed once.
Enumerable has a grep
method whose first argument can be a predicate proc, and whose optional second argument is a mapping function; so the following works:
some_array.grep(proc {|x| x % 2 == 0}) {|x| x*3}
This isn't as readable as a couple of other suggestions (I like anoiaque's simple select.map
or histocrat's comprehend gem), but its strengths are that it's already part of the standard library, and is single-pass and doesn't involve creating temporary intermediate arrays, and doesn't require an out-of-bounds value like nil
used in the compact
-using suggestions.
How 'bout:
some_array.map {|x| x % 2 == 0 ? x * 3 : nil}.compact
Slightly cleaner, at least to my taste, and according to a quick benchmark test about 15% faster than your version...
[1, 2, 3, 4, 5, 6].collect{|x| x * 3 if x % 2 == 0}.compact
=> [6, 12, 18]
That works for me. It is also clean. Yes, it's the same as map
, but I think collect
makes the code more understandable.
select(&:even?).map()
actually looks better, after seeing it below.
Like Pedro mentioned, you can fuse together the chained calls to Enumerable#select
and Enumerable#map
, avoiding a traversal over the selected elements. This is true because Enumerable#select
is a specialization of fold or inject
. I posted a hasty introduction to the topic at the Ruby subreddit.
Manually fusing Array transformations can be tedious, so maybe someone could play with Robert Gamble's comprehend
implementation to make this select
/map
pattern prettier.
Another solution but perhaps not the best one
some_array.flat_map {|x| x % 2 == 0 ? [x * 3] : [] }
or
some_array.each_with_object([]) {|x, list| x % 2 == 0 ? list.push(x * 3) : nil }