99

Python のリスト内包表記と同等の処理を行うために、次のようにしています。

some_array.select{|x| x % 2 == 0 }.collect{|x| x * 3}

これを行うためのより良い方法はありますか...おそらく1つのメソッド呼び出しで?

4

17 に答える 17

94

どうですか:

some_array.map {|x| x % 2 == 0 ? x * 3 : nil}.compact

少なくとも私の好みでは、わずかにきれいで、簡単なベンチマーク テストによると、あなたのバージョンよりも約 15% 高速です...

于 2008-11-22T01:39:59.730 に答える
56

本当にしたい場合は、次のように Array#comprehend メソッドを作成できます。

class Array
  def comprehend(&block)
    return self if block.nil?
    self.collect(&block).compact
  end
end

some_array = [1, 2, 3, 4, 5, 6]
new_array = some_array.comprehend {|x| x * 3 if x % 2 == 0}
puts new_array

版画:

6
12
18

私はおそらくあなたがしたようにそれをするでしょう。

于 2008-11-21T22:47:16.003 に答える
31

3 つの選択肢を比較する簡単なベンチマークを作成しましたが、map-compactが実際に最適なオプションのようです。

パフォーマンス テスト (Rails)

require 'test_helper'
require 'performance_test_help'

class ListComprehensionTest < ActionController::PerformanceTest

  TEST_ARRAY = (1..100).to_a

  def test_map_compact
    1000.times do
      TEST_ARRAY.map{|x| x % 2 == 0 ? x * 3 : nil}.compact
    end
  end

  def test_select_map
    1000.times do
      TEST_ARRAY.select{|x| x % 2 == 0 }.map{|x| x * 3}
    end
  end

  def test_inject
    1000.times do
      TEST_ARRAY.inject([]) {|all, x| all << x*3 if x % 2 == 0; all }
    end
  end

end

結果

/usr/bin/ruby1.8 -I"lib:test" "/usr/lib/ruby/gems/1.8/gems/rake-0.8.7/lib/rake/rake_test_loader.rb" "test/performance/list_comprehension_test.rb" -- --benchmark
Loaded suite /usr/lib/ruby/gems/1.8/gems/rake-0.8.7/lib/rake/rake_test_loader
Started
ListComprehensionTest#test_inject (1230 ms warmup)
           wall_time: 1221 ms
              memory: 0.00 KB
             objects: 0
             gc_runs: 0
             gc_time: 0 ms
.ListComprehensionTest#test_map_compact (860 ms warmup)
           wall_time: 855 ms
              memory: 0.00 KB
             objects: 0
             gc_runs: 0
             gc_time: 0 ms
.ListComprehensionTest#test_select_map (961 ms warmup)
           wall_time: 955 ms
              memory: 0.00 KB
             objects: 0
             gc_runs: 0
             gc_time: 0 ms
.
Finished in 66.683039 seconds.

15 tests, 0 assertions, 0 failures, 0 errors
于 2011-02-18T20:13:35.490 に答える
12

このスレッドでは、リスト内包表記とは何かについて、Ruby プログラマーの間で混乱が生じているようです。すべての応答は、変換する既存の配列を前提としています。しかし、リスト内包表記の力は、次の構文でオンザフライで作成される配列にあります。

squares = [x**2 for x in range(10)]

以下はRubyの類似物です(このスレッドでの唯一の適切な答え、AFAIC):

a = Array.new(4).map{rand(2**49..2**50)} 

上記の場合、ランダムな整数の配列を作成していますが、ブロックには何でも含めることができます。しかし、これは Ruby のリスト内包表記になります。

于 2012-03-26T23:26:47.297 に答える
11

私はこのトピックについてReinHenrichsと話し合いました。彼は、最高のパフォーマンスを発揮するソリューションは

map { ... }.compact

Enumerable#injectこれは、の不変の使用法のように中間配列を構築することを回避し、割り当ての原因となる配列の拡張を回避するため、理にかなっています。コレクションにnil要素を含めることができない限り、他の要素と同じくらい一般的です。

私はこれを比較していません

select {...}.map{...}

RubyのC実装Enumerable#selectも非常に優れている可能性があります。

于 2010-05-04T01:51:24.893 に答える
9

すべての実装で機能し、O(2n) 時間ではなく O(n) で実行される代替ソリューションは次のとおりです。

some_array.inject([]){|res,x| x % 2 == 0 ? res << 3*x : res}
于 2010-05-02T16:49:30.427 に答える
8

Comprehend gemを RubyGems に公開したところ、次のことが可能になります。

require 'comprehend'

some_array.comprehend{ |x| x * 3 if x % 2 == 0 }

C で書かれています。配列は 1 回だけトラバースされます。

于 2013-02-15T19:23:01.337 に答える
4
[1, 2, 3, 4, 5, 6].collect{|x| x * 3 if x % 2 == 0}.compact
=> [6, 12, 18]

それは私にとってはうまくいきます。それもきれいです。はい、と同じですが、コードがわかりやすくなるmapと思います。collect


select(&:even?).map()

以下でそれを見た後、実際には良く見えます。

于 2010-05-03T16:37:45.280 に答える
4

これはより簡潔です:

[1,2,3,4,5,6].select(&:even?).map{|x| x*3}
于 2010-05-03T22:09:20.260 に答える
2

Enumerable#selectPedro が述べたように、チェーンされたandへの呼び出しを融合してEnumerable#map、選択した要素のトラバーサルを回避できます。Enumerable#selectは fold または の特殊化であるため、これは真ですinject。Ruby subreddit に、このトピックについての拙速な紹介を投稿しました。

配列変換を手動で融合するのは面倒な場合があるため、誰かが Robert Gamble のcomprehend実装で遊んで、このselect/mapパターンをよりきれいにすることができます。

于 2010-05-03T18:32:39.933 に答える
2

このようなもの:

def lazy(collection, &blk)
   collection.map{|x| blk.call(x)}.compact
end

あれを呼べ:

lazy (1..6){|x| x * 3 if x.even?}

どちらが返されますか:

=> [6, 12, 18]
于 2013-04-17T04:41:43.563 に答える
-3

最もリストの理解に近いものは次のようになると思います。

some_array.select{ |x| x * 3 if x % 2 == 0 }

Ruby では式の後に条件を配置できるため、リスト内包表記の Python バージョンと同様の構文が得られます。また、selectメソッドには と同等のものは含まれないため、すべての nil 値が結果のリストから削除され、代わりにorfalseを使用した場合のように、compact を呼び出す必要はありません。mapcollect

于 2009-10-24T01:51:18.387 に答える