List comprehension in Ruby

后端 未结 17 2141
广开言路
广开言路 2020-12-02 07:01

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

相关标签:
17条回答
  • 2020-12-02 07:44

    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.

    0 讨论(0)
  • 2020-12-02 07:46

    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.

    0 讨论(0)
  • 2020-12-02 07:49

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

    0 讨论(0)
  • 2020-12-02 07:50
    [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.

    0 讨论(0)
  • 2020-12-02 07:50

    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.

    0 讨论(0)
  • 2020-12-02 07:50

    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 }
    
    0 讨论(0)
提交回复
热议问题