배열에 다른 배열의 값이 포함되어 있습니까?


155

배열에 두 번째 배열의 요소가 포함되어 있는지 테스트하는 가장 효율적인 방법은 무엇입니까?

아래 질문에 대한 답변을 시도하는 두 가지 예 foods에는 다음과 같은 요소 가 포함됩니다 cheeses.

cheeses = %w(chedder stilton brie mozzarella feta haloumi reblochon)
foods = %w(pizza feta foods bread biscuits yoghurt bacon)

puts cheeses.collect{|c| foods.include?(c)}.include?(true)

puts (cheeses - foods).size < cheeses.size

답변:


268
(cheeses & foods).empty?

Marc-André Lafortune이 논평에서 말했듯 &이 선형 시간으로 작동하지만 any?+ include?는 2 차입니다. 더 큰 데이터 세트의 경우 선형 시간이 더 빠릅니다. 작은 데이터 세트의 경우 Lee Jarvis의 답변에서 볼 수 있듯이 any?+ include?가 빠를 수 있습니다. 아마도 &다른 솔루션이 새 배열을 할당하지 않고 부울을 반환하는 간단한 중첩 루프로 작동 하기 때문일 수 있습니다.


3
배열에 다른 배열의 요소가 포함되어 있는지 확인할 때 (치즈 및 음식) 더 이해가되지 않습니까? 실제로 배열에 동일한 요소가 포함되어 있으면 실제 값을 반환합니까?
라이언 프랜시스

1
@RyanFrancis, docs : any?: 블록이 false 또는 nil 이외의 값을 반환하면이 메서드는 true를 반환합니다. empty?: self에 요소가 없으면 true를 리턴합니다.
Nakilon

3
@ Nakilon 나는 또한 대답이 왜 (cheeses & foods).any?OP 가 아닌지 혼란 스럽습니다 : 치즈에 음식이 있다면? 그의 예에서 "feta"는 둘 다에 있으므로 결과는 사실입니까? 왜 .empty?교차로를 확인 합니까?
SuckerForMayhem

@SuckerForMayhem, OP의 질문은 "만약 있다면 ?"이 아니라 "만약 있다면 ... ?"입니다. " are ... "를 생략하면 "If any is True? " 라고 가정하고 배열 [false, false, false]이 비어있는 동안 False를 반환 합니다.
Nakilon

활성 레코드 레벨에 구현이 있습니까?
이춘호

35

방법에 대한 Enumerable에서 번호 어떤?

>> cheeses = %w(chedder stilton brie mozzarella feta haloumi)
=> ["chedder", "stilton", "brie", "mozzarella", "feta", "haloumi"]
>> foods = %w(pizza feta foods bread biscuits yoghurt bacon)
=> ["pizza", "feta", "foods", "bread", "biscuits", "yoghurt", "bacon"]
>> foods.any? {|food| cheeses.include?(food) }
=> true

벤치 마크 스크립트 :

require "benchmark"
N = 1_000_000
puts "ruby version: #{RUBY_VERSION}"

CHEESES = %w(chedder stilton brie mozzarella feta haloumi).freeze
FOODS = %w(pizza feta foods bread biscuits yoghurt bacon).freeze

Benchmark.bm(15) do |b|
  b.report("&, empty?") { N.times { (FOODS & CHEESES).empty? } }
  b.report("any?, include?") { N.times { FOODS.any? {|food| CHEESES.include?(food) } } }
end

결과:

ruby version: 2.1.9
                      user     system      total        real
&, empty?         1.170000   0.000000   1.170000 (  1.172507)
any?, include?    0.660000   0.000000   0.660000 (  0.666015)

cheeses세트로 바꾸면이를 개선 할 수 있습니다 .
akuhn

1
루비 2.2.7 및 2.3.4에서 내 벤치 마크 any?, include?를 실행했으며 가장 빠르며 가장 느리게 설정했습니다 : gist.github.com/jaredmoody/d2a1e83de2f91fd6865920cd01a8b497
Jared

4
이 벤치 마크는 언급 된 특정 예에 의해 편향되어 있으며 더 일반적인 경우는 아닙니다. 두 배열 사이에 공통 요소가 없으면 어떻게합니까? 각 패스에서 배열의 순서가 다른 경우 어떻게됩니까? 태아가 두 배열의 끝에 나타나면 어떻게해야합니까? Marc-André가 언급했듯이, 집합 교차는 선형 시간으로 실행되므로 문제를 명확히하기 위해 순수하게 사용 된 하나의 특정 예가 아니라 일반적인 경우에 훨씬 더 확장 가능하다는 것이 합리적입니다.
user2259664

22

교차점이 비어 있는지 확인할 수 있습니다.

cheeses = %w(chedder stilton brie mozzarella feta haloumi)
foods = %w(pizza feta foods bread biscuits yoghurt bacon)
foods & cheeses
=> ["feta"] 
(foods & cheeses).empty?
=> false

1
Set.new(cheeses).disjoint? Set.new(foods)

또한 내 (비과학적인) 벤치 마크에서 set disjoint는 다른 방법보다 상당히 느 렸습니다. gist.github.com/jaredmoody/d2a1e83de2f91fd6865920cd01a8b497
Jared

1
귀하의 의견에 감사드립니다. 왜 Set.new가 아닌지 잘 모르겠지만 방금 편집했습니다. 2.4.1에서 성능 벤치 마크를 시도했습니다. 광산은 더 많은 단어를 포함하는 분리 된 세트를 사용하는 것이 좋지만 여전히 최선은 아닙니다. 나는 당신의 요점에 대한 의견에 내 버전을 넣었습니다. 나는 또한 disjoint?"어떤?, 포함?"에 비해 매우 우아 하다고 생각 합니다. 원래의 질문은 우아하고 효율적입니다.
davidkovsky

.to_set이 방법은 유용 할 수 있습니다cheeses.to_set.disjoint?(foods.to_set)
itsnikolay

0
require "benchmark"
N = 1_000_000
puts "ruby version: #{RUBY_VERSION}"

CHEESES = %w(chedder stilton brie mozzarella feta haloumi).freeze
FOODS = %w(pizza feta foods bread biscuits yoghurt bacon).freeze

Benchmark.bm(15) do |b|
  b.report("&, empty?") { N.times { (FOODS & CHEESES).empty? } }  
  b.report("any?, include?") { N.times { FOODS.any? {|food| CHEESES.include?(food) } } }  
  b.report("disjoint?") { N.times { FOODS.to_set.disjoint? CHEESES.to_set }}
end  
                      user     system      total        real
&, empty?         0.751068   0.000571   0.751639 (  0.752745)
any?, include?    0.408251   0.000133   0.408384 (  0.408438)
disjoint?        11.616006   0.014806  11.630812 ( 11.637300)
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.