2014-01-29 3 views
0

아마도 좀더 일반적인 질문은 Ruby에서 목록 이해하는 것입니다.Ruby : 두 개의 다른 배열을 결합하고 인터리브하여 배열을 만드는 방법

수 N 부여의가 있다고 가정 해 봅시다 (= N 말 5) 나는이 같은 배열 싶어 : 내가 할 수있는 필수 방법을 사용

[[0, 1], [0, 2], [0, 3], [0, 4], [1, 2], [1, 3], [1, 4], [2, 3], [2, 4], [3, 4]] 

을 :

arr = [] 
    N = 5 
    (0..N-1).each do |i| 
    (i+1..N-1).each do |j| 
     arr << [i, j] 
    end 
    end 
    puts arr 

기능적인 방법을 사용 :

(0..N-1).collect{|el1| (el1+1..N-1).collect{|el2| [el1, el2]}}.flatten.each_slice(2).to_a 

두 번째 예제는 배열이 올바른 순서로 정렬된다는 사실에 의존합니다. 기능적인 방법으로 배열을 가져 오는 더 깨끗한 방법이 있습니까 (추가 병열 및 조각 제외)?

답변

2
나는 다음과 같이 할 것

:

n = 5 
a = n.times.flat_map do |i| 
    [i].product (i+1..n-1).to_a 
end 
a # => [[0, 1], [0, 2], [0, 3], [0, 4], [1, 2], [1, 3], [1, 4], [2, 3], [2, 4], [3, 4]] 
+0

감사합니다. Arup! 여기서 flat_map이 핵심입니다 : (0..N-1) .flat_map {| el1 | (el1 + 1..N-1) .map {| el2 | [el1, el2]}} – Andrei

+1

또한 배열을 조합 할 때 제품 기능이 매우 강력합니다. 배열에서 오는 두 숫자의 모든 순열을 얻기 위해 전에 사용했습니다. 아주 아름다운 응용 프로그램, Arup, 고마워. – Andrei

1

당신은이 작업을 수행 할 수 있습니다 :

좋은 보이지만, 그것은 N을 생성하는 단점이있다
Array(0...N).combination(2).to_a 

/(4 * (N-2!)!) 조합은 사용하지 않습니다.

편집 : 원래 위의 to_a 대신 select { |x,y| x < y }이있었습니다. @Stefan은 select이 과도하지 않다고 지적했다. 어쩌면 나는 뇌에 permutation(2)을 가졌을 것입니다. 그것을 할 수

a = Array(0...N) 
a.size.times.reduce([]) { |b,_| b + [a.shift].product(a) } 
+2

'(0 ... 5) .to_a.combination (2) .to_a'는 같은 배열을 반환합니까? – Stefan

+0

@Stefan이 답변으로 만듭니다 .. 좋은 분! –

+1

더 정확하게 말하자면 : .select {| x, y | x Stefan

0

가장 효율적인 방법 스테판이다, 캐리의 대답에 주석했다 (이 답변에 Arup에의 코멘트에 n 변수를 사용하도록 수정 : 여기

은 Arup에의 대답 @의 변종 또 다른 방법), 모든 사람에게 캐리의 대답에서 수정, 그래서 일이었다 :

2.1.0p0 :001 > n = 5 
=> 5 
2.1.0p0 :002 > a = (0...n).to_a.combination(2).to_a 
=> [[0, 1], [0, 2], [0, 3], [0, 4], [1, 2], [1, 3], [1, 4], [2, 3], [2, 4], [3, 4]] 

일부 벤치 마크 :

2.1.0p0 :001 > require 'benchmark' 
=> true 
2.1.0p0 :002 > n = 5 
=> 5 
2.1.0p0 :003 > puts Benchmark.measure { 1000000.times { a = n.times.flat_map {|i| [i].product (i+1..n-1).to_a} } } 
    8.050000 0.010000 8.060000 ( 8.051535) 
=> nil 
2.1.0p0 :004 > puts Benchmark.measure { 1000000.times { a = n.times.flat_map {|x| (x+1..n-1).map{|y| [x,y]}} } } 
    6.250000 0.000000 6.250000 ( 6.249600) 
=> nil 
2.1.0p0 :005 > puts Benchmark.measure { 1000000.times { a = Array(0...n).combination(2).select { |x,y| x < y } } } 
    5.110000 0.010000 5.120000 ( 5.120506) 
=> nil 
2.1.0p0 :006 > puts Benchmark.measure { 1000000.times { a = n.times.to_a.combination(2).to_a } } 
    4.050000 0.000000 4.050000 ( 4.045895) 
=> nil 
2.1.0p0 :007 > puts Benchmark.measure { 1000000.times { a = Array(0...n).combination(2).to_a } } 
    3.920000 0.000000 3.920000 ( 3.928282) 
=> nil 
2.1.0p0 :008 > puts Benchmark.measure { 1000000.times { a = (0...n).to_a.combination(2).to_a } } 
    3.520000 0.000000 3.520000 ( 3.522056) 
=> nil 
+1

하지만'(0 ... 5) .to_a.combination (2) .to_a'가 더 읽기 쉽습니다 .. –

+0

Arup - 방금 언급 한 내용이 더 빨리 벤치마킹되어 답변이 변경되었습니다. –

관련 문제