program tip

배열에 객체가 포함되어 있는지 확인하려면 어떻게합니까?

radiobox 2020. 10. 23. 07:44
반응형

배열에 객체가 포함되어 있는지 확인하려면 어떻게합니까?


@horses = []무작위 말로 채울 배열 이 있습니다.

@horses배열에 이미 포함 된 (존재하는) 말이 포함되어 있는지 어떻게 확인할 수 있습니까?

나는 다음과 같은 것을 시도했다.

@suggested_horses = []
  @suggested_horses << Horse.find(:first,:offset=>rand(Horse.count))
  while @suggested_horses.length < 8
    horse = Horse.find(:first,:offset=>rand(Horse.count))
    unless @suggested_horses.exists?(horse.id)
       @suggested_horses<< horse
    end
  end

나도 함께 시도 include?했지만 문자열 전용이라는 것을 알았습니다. exists?나는 다음과 같은 오류가 발생합니다 :

undefined method `exists?' for #<Array:0xc11c0b8>

그래서 질문은 내 배열에 이미 "말"이 포함되어 있는지 확인하여 동일한 말로 채우지 않도록하는 방법입니다.


Ruby의 배열에는 exists?메서드가 없지만 문서에 설명 된include? 메서드 있습니다. 같은 것

unless @suggested_horses.include?(horse)
   @suggested_horses << horse
end

상자에서 작동해야합니다.


객체의 속성을 확인하여 객체가 배열 내에 있는지 확인 any?하려면 true 또는 false로 평가되는 블록을 사용 하고 전달할 수 있습니다 .

unless @suggested_horses.any? {|h| h.id == horse.id }
  @suggested_horses << horse
end

이유는 간단에서 8 개 개의 서로 다른 번호를 선택하여 그것을 할 0Horse.count당신의 말을 얻는 것을 사용?

offsets = (0...Horse.count).to_a.sample(8)
@suggested_horses = offsets.map{|i| Horse.first(:offset => i) }

이것은 데이터베이스에 8 마리 미만의 말이있는 경우 무한 루프를 일으키지 않는다는 추가 이점이 있습니다.

참고 : Array#sample 은 1.9의 새로운 기능 (1.8.8에서 제공)이므로 Ruby를 업그레이드 require 'backports'하거나 shuffle.first(n).


#include?작동해야 하며 문자열뿐만 아니라 일반 객체 에서도 작동합니다 . 예제 코드의 문제는 다음 테스트입니다.

unless @suggested_horses.exists?(horse.id)
  @suggested_horses<< horse
end

(를 사용한다고 가정해도 #include?). id가 아닌 특정 개체를 검색하려고합니다. 따라서 다음과 같아야합니다.

unless @suggested_horses.include?(horse)
  @suggested_horses << horse
end

ActiveRecord는 상태 (새로 만들기 / 생성됨) 및 ID 만 확인하도록 개체에 대한 비교 연산자를 재정의 했습니다.


Array의 include?메서드는 문자열뿐만 아니라 모든 객체를 허용합니다. 이것은 작동합니다.

@suggested_horses = [] 
@suggested_horses << Horse.first(:offset => rand(Horse.count)) 
while @suggested_horses.length < 8 
  horse = Horse.first(:offset => rand(Horse.count)) 
  @suggested_horses << horse unless @suggested_horses.include?(horse)
end

그래서 질문은 내 배열에 이미 "말"이 포함되어 있는지 확인하여 동일한 말로 채우지 않도록하는 방법입니다.

대답은 특정 문자열이나 객체가 있는지 확인하기 위해 배열을 살펴 보는 것과 관련이 있지만 배열이 커질수록 검색 시간이 더 오래 걸리기 때문에 실제로는 잘못된 것입니다.

대신 Hash 또는 Set을 사용하십시오 . 둘 다 특정 요소의 단일 인스턴스 만 허용합니다. Set은 배열에 더 가깝게 동작하지만 단일 인스턴스 만 허용합니다. 이는 컨테이너의 특성으로 인해 중복을 방지하는보다 선제적인 접근 방식입니다.

hash = {}
hash['a'] = nil
hash['b'] = nil
hash # => {"a"=>nil, "b"=>nil}
hash['a'] = nil
hash # => {"a"=>nil, "b"=>nil}

require 'set'
ary = [].to_set
ary << 'a'
ary << 'b'
ary # => #<Set: {"a", "b"}>
ary << 'a'
ary # => #<Set: {"a", "b"}>

Hash는 이름 / 값 쌍을 사용하므로 값이 실제로 사용되지는 않지만 일부 테스트에 따르면 Hash를 사용하면 약간의 추가 속도가있는 것 같습니다.

require 'benchmark'
require 'set'

ALPHABET = ('a' .. 'z').to_a
N = 100_000
Benchmark.bm(5) do |x|
  x.report('Hash') { 
    N.times {
      h = {}
      ALPHABET.each { |i|
        h[i] = nil
      }
    }
  }

  x.report('Array') {
    N.times {
      a = Set.new
      ALPHABET.each { |i|
        a << i
      }
    }
  }
end

출력되는 내용 :

            user     system      total        real
Hash    8.140000   0.130000   8.270000 (  8.279462)
Array  10.680000   0.120000  10.800000 ( 10.813385)

이 ...

horse = Horse.find(:first,:offset=>rand(Horse.count))
unless @suggested_horses.exists?(horse.id)
   @suggested_horses<< horse
end

아마 이것이어야 ...

horse = Horse.find(:first,:offset=>rand(Horse.count))
unless @suggested_horses.include?(horse)
   @suggested_horses<< horse
end

참고 URL : https://stackoverflow.com/questions/3343861/how-do-i-check-to-see-if-my-array-includes-an-object

반응형