한 배열에 다른 배열의 모든 요소가 포함되어 있는지 확인하는 방법


179

주어진:

a1 = [5, 1, 6, 14, 2, 8]

다음의 모든 요소가 포함되어 있는지 확인하고 싶습니다.

a2 = [2, 6, 15]

이 경우 결과는 false입니다.

그러한 배열 포함을 식별하는 내장 Ruby / Rails 메소드가 있습니까?

이를 구현하는 한 가지 방법은 다음과 같습니다.

a2.index{ |x| !a1.include?(x) }.nil?

더 좋고 더 읽기 쉬운 방법이 있습니까?


허용되는 답변 (배열 빼기)이 가장 빠른 솔루션입니다. 여기 그들 모두를 벤치마킹 : gist.github.com/bbugh/cbbde8b48cbb16286044f6893e1f2e5f
brainbag

답변:


309
a = [5, 1, 6, 14, 2, 8]
b = [2, 6, 15]

a - b
=> [5, 1, 14, 8]

b - a
=> [15]

(b - a).empty?
=> false

61
이것은 갈 길입니다. 그것은 조금이 단축 될 수있다(a2-a1).empty?
홀거 그냥

9
이것은 복제 된 배열이 아닌 세트 인 배열에만 적용됩니다.
Chris

3
@Chris-Array # uniq를 사용해 볼 수 있습니다. 홀거 단의 예, 그것은 것(a2.uniq - a1.uniq).empty?

stackoverflow.com/questions/13553822/… 는 내가 의미 한 바입니다. Array # unique는 명시 적으로 실패합니다.
Chris

81

아마도 이것은 더 읽기 쉽습니다.

a2.all? { |e| a1.include?(e) }

배열 교차를 사용할 수도 있습니다.

(a1 & a2).size == a1.size

참고 size단지 속도 여기에 사용됩니다, 당신은 또한 (느리게) 할 수 있습니다 :

(a1 & a2) == a1

그러나 첫 번째가 더 읽기 쉽다고 생각합니다. 이 3 개는 일반 루비입니다 (레일 아님).


a1과 a2의 OP의 정의와 a2의 "모든 요소를 ​​포함하는"a1을 사용하는 경우 a2가 더 작은 배열이기 때문에 이것이 _ (a1 & a2) .size == a2.size _이어야한다고 생각합니다. 더 큰 배열에 포함 된 요소 ( 'true'를 얻기 위해)-따라서 모든 배열이 더 큰 배열에있는 경우 두 배열의 교차는 더 작은 배열과 동일한 길이 여야합니다.
JosephK

57

이것은 수행하여 달성 할 수 있습니다

(a2 & a1) == a2

그러면 두 배열의 교집합이 만들어지고 a2in에있는 모든 요소가 반환 됩니다 a1. 결과가와 동일 a2하면 모든 요소가에 포함되어 있는지 확인할 수 있습니다 a1.

이 방법은 모든 요소 a2가 처음에 서로 다른 경우에만 작동합니다 . 복식이 있으면이 방법은 실패합니다. Tempos의 것이 여전히 작동하므로 전적으로 그의 접근 방식을 추천합니다 (아마도 더 빠릅니다).


2
사용 length방법은 훨씬 더 수행합니다
파블로 페르난데스에게

3
교차 세트가 동일한 순서로 다른 요소를 가진 경우에는 작동하지 않습니다. 이 질문에 대답하는 동안 나는 어려운 방법에서 이걸 발견 : stackoverflow.com/questions/12062970/... 나중에 실현 많은 스마트 사람들은 이미 여기했었다!
CubaLibre

1
@CubaLibre 재미있는. 이것을 재현 할 테스트 데이터가 있습니까? 내 테스트는 결과 배열이 첫 번째 배열의 요소 순서를 유지하는 것처럼 보였습니다 (따라서 가장 최근의 편집 결과는 내 대답입니다). 그러나 이것이 사실이 아닌 경우 배우고 싶습니다.
Holger 단지

@HolgerJager (a2 & a1) 대신 (a1 & a2)를하는 실수를 저질렀 기 때문에 오류가 발생했습니다. 첫 번째 배열의 주문을 유지하고 있습니다.
CubaLibre

10

중복 요소가 없거나 신경 쓰지 않으면 Set 클래스를 사용할 수 있습니다 .

a1 = Set.new [5, 1, 6, 14, 2, 8]
a2 = Set.new [2, 6, 15]
a1.subset?(a2)
=> false

이 장면 뒤에서

all? { |o| set.include?(o) }

1

Array 클래스를 원숭이 패치 할 수 있습니다.

class Array
    def contains_all?(ary)
        ary.uniq.all? { |x| count(x) >= ary.count(x) }
    end
end

테스트

irb(main):131:0> %w[a b c c].contains_all? %w[a b c]
=> true
irb(main):132:0> %w[a b c c].contains_all? %w[a b c c]
=> true
irb(main):133:0> %w[a b c c].contains_all? %w[a b c c c]
=> false
irb(main):134:0> %w[a b c c].contains_all? %w[a]
=> true
irb(main):135:0> %w[a b c c].contains_all? %w[x]
=> false
irb(main):136:0> %w[a b c c].contains_all? %w[]
=> true
irb(main):137:0> %w[a b c d].contains_all? %w[d c h]
=> false
irb(main):138:0> %w[a b c d].contains_all? %w[d b c]
=> true

물론이 방법은 표준 단독 방법으로 작성 될 수 있습니다.

def contains_all?(a,b)
    b.uniq.all? { |x| a.count(x) >= b.count(x) }
end

그리고 당신은 그것을 호출 할 수 있습니다

contains_all?(%w[a b c c], %w[c c c])

실제로 프로파일 링 후 다음 버전이 훨씬 빠르며 코드가 더 짧습니다.

def contains_all?(a,b)
    b.all? { |x| a.count(x) >= b.count(x) }
end

0

배열의 크기에 따라 효율적인 알고리즘 O (n log n)을 고려할 수 있습니다.

def equal_a(a1, a2)
  a1sorted = a1.sort
  a2sorted = a2.sort
  return false if a1.length != a2.length
  0.upto(a1.length - 1) do 
    |i| return false if a1sorted[i] != a2sorted[i]
  end
end

정렬 비용 O (n log n) 및 각 쌍을 확인하는 데 비용 O (n)이 있으므로이 알고리즘은 O (n log n)입니다. 정렬되지 않은 배열을 사용하면 다른 알고리즘이 더 빠를 수 없습니다.


카운팅 정렬을 사용하여 O (n)에서 수행 할 수 있습니다.
klochner

아니 당신은 할 수 없습니다. 카운팅 정렬은 제한된 유니버스를 사용하며 Ruby는 큰 숫자를 얻는 방법에 대한 제한이 없습니다.
ayckoster

실제로 항목을 정렬 할 필요가 없기 때문에 해시 매핑 항목이 필요합니다. 두 배열을 모두 계산 한 다음 키를 반복하고 카운트를 비교하십시오.
klochner

Array # sort가 병합 정렬을 사용합니까?
Nate Symer

0

(a1-a2) 또는 (a1 & a2)를 기반으로하는 대부분의 답변은 두 배열에 중복 된 요소가있는 경우 작동하지 않습니다. 나는 단어의 모든 문자 (배열에 쪼개짐)가 문자 세트의 일부인지 (예 : 글자 맞추기) 방법을 찾기 위해 여기에 도착했습니다. 이 답변들 중 어느 것도 효과가 없었지만, 이것은 하나

def contains_all?(a1, a2)
  try = a1.chars.all? do |letter|
    a1.count(letter) <= a2.count(letter)
  end
  return try
end
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.