Python 목록 이해와 동등한 작업을 수행하기 위해 다음을 수행합니다.
some_array.select{|x| x % 2 == 0 }.collect{|x| x * 3}
이 작업을 수행하는 더 좋은 방법이 있습니까? 아마 하나의 메서드 호출로?
답변
정말로 원한다면 다음과 같이 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
나는 아마 당신이했던 방식대로 할 것입니다.
답변
어때?
some_array.map {|x| x % 2 == 0 ? x * 3 : nil}.compact
적어도 내 취향에는 약간 깨끗하고 빠른 벤치 마크 테스트에 따르면 귀하의 버전보다 약 15 % 더 빠릅니다.
답변
세 가지 대안을 비교하는 빠른 벤치 마크를 만들었고 map-compact가 정말 최선의 선택 인 것 같습니다.
성능 테스트 (레일)
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
답변
목록 이해력이 무엇인지에 대해이 스레드에서 Ruby 프로그래머 사이에 약간의 혼란이있는 것 같습니다. 모든 단일 응답은 변환 할 기존 배열을 가정합니다. 그러나 목록 이해력의 힘은 다음 구문으로 즉석에서 생성 된 배열에 있습니다.
squares = [x**2 for x in range(10)]
다음은 Ruby의 아날로그입니다 (이 스레드의 유일한 적절한 대답 인 AFAIC).
a = Array.new(4).map{rand(2**49..2**50)}
위의 경우 임의의 정수 배열을 생성하고 있지만 블록에는 모든 것이 포함될 수 있습니다. 그러나 이것은 Ruby 목록 이해입니다.
답변
Rein Henrichs와이 주제에 대해 논의했습니다. Rein Henrichs는 최고의 성능을내는 솔루션은
map { ... }.compact
이는의 변경 불가능한 사용과 같이 중간 배열을 빌드 Enumerable#inject
하는 것을 피하고 할당을 유발하는 배열의 증가를 방지하기 때문에 합리적 입니다. 컬렉션에 nil 요소가 포함될 수없는 경우가 아니면 다른 것만 큼 일반적입니다.
나는 이것을 비교하지 않았다
select {...}.map{...}
Ruby의 C 구현 Enumerable#select
도 매우 훌륭 할 수 있습니다.
답변
모든 구현에서 작동하고 O (2n) 시간 대신 O (n)에서 실행되는 대체 솔루션은 다음과 같습니다.
some_array.inject([]){|res,x| x % 2 == 0 ? res << 3*x : res}
답변
방금 Comprehend gem 을 RubyGems에 게시 했습니다. 이렇게하면 다음과 같이 할 수 있습니다.
require 'comprehend'
some_array.comprehend{ |x| x * 3 if x % 2 == 0 }
C로 작성되었습니다. 어레이는 한 번만 순회됩니다.