etc./StackOverFlow

Ruby에서 배열에 값이 있는지 확인하는 방법

청렴결백한 만능 재주꾼 2022. 3. 22. 11:04
반응형

질문자 :user211662


나는 값 'Dog' 와 배열 ['Cat', 'Dog', 'Bird'] 있습니다.

반복하지 않고 배열에 존재하는지 어떻게 확인합니까? 값이 존재하는지 확인하는 간단한 방법이 있습니까?



include? 찾고 계십니까? :

 >> ['Cat', 'Dog', 'Bird'].include? 'Dog' => true

Brian Campbell

에 있다 in? @campaterson이 지적한 것처럼 v3.1부터 ActiveSupport (Rails의 일부)의 메서드 입니다. 따라서 Rails 내에서 또는 require 'active_support' 경우 다음과 같이 작성할 수 있습니다.

 'Unicorn'.in?(['Cat', 'Dog', 'Bird']) # => false

OTOH, 더는 없다 in 운영자 또는 #in? Ruby-core의 최고 수준 멤버인 Yusuke Endoh 가 이전에 제안했지만 Ruby 자체의 방법입니다.

다른 사람들이 지적했듯이 반대 방법 include? Array , Hash , Set , Range 포함한 Enumerable 대해 존재합니다.

 ['Cat', 'Dog', 'Bird'].include?('Unicorn') # => false

배열에 많은 값이 있는 경우 해시에 대한 조회는 일정한 시간(즉, O(1) )인 반면에 모두 차례로 검사됩니다(즉, O(n) ) ). 따라서 예를 들어 배열이 상수인 경우 대신 Set을 사용하는 것이 좋습니다. 예:

 require 'set' ALLOWED_METHODS = Set[:to_s, :to_i, :upcase, :downcase # etc ] def foo(what) raise "Not allowed" unless ALLOWED_METHODS.include?(what.to_sym) bar.send(what) end

빠른 테스트 는 호출이 include? 10개 요소에서 Set Array (요소를 찾을 수 없는 경우)에서 호출하는 것보다 약 3.5배 빠릅니다.

마지막 마무리 메모: include? Range 에는 미묘한 부분이 있으므로 문서를 참조하고 표지와 비교 cover? ...


Marc-André Lafortune

노력하다

 ['Cat', 'Dog', 'Bird'].include?('Dog')

schmitzelburger

블록별로 확인하고 싶다면 any? 아니면 all? .

 %w{ant bear cat}.any? {|word| word.length >= 3} #=> true %w{ant bear cat}.any? {|word| word.length >= 4} #=> true [ nil, true, 99 ].any? #=> true

자세한 내용은 열거 가능 을 참조하십시오.

내 영감은 " 배열에 루비 항목이 있는지 평가"에서 나왔습니다.


Xiaofan Hu

Enumerable#include :

 a = %w/Cat Dog Bird/ a.include? 'Dog'

테스트의 숫자가 완료되는 경우 또는, (1) 당신은 루프를 제거 (심지어 것을 얻을 수 include? 하고있다)과와 O (1)로 O (N)에서 이동 :

 h = Hash[[a, a].transpose] h['Dog']


1. 이것이 분명하기를 바라지만 반대를 피하기 위해: 예, 단지 몇 번의 조회를 위해 Hash[] 및 transpose 연산이 프로필을 지배하고 각각 O(n) 자체입니다.


DigitalRoss

Ruby에는 배열에서 요소를 찾는 11가지 방법이 있습니다.

선호하는 것은 include? 또는 반복적인 액세스를 위해 Set을 생성한 다음 include? 또는 member? .

다음은 모두 다음과 같습니다.

 array.include?(element) # preferred method array.member?(element) array.to_set.include?(element) array.to_set.member?(element) array.index(element) > 0 array.find_index(element) > 0 array.index { |each| each == element } > 0 array.find_index { |each| each == element } > 0 array.any? { |each| each == element } array.find { |each| each == element } != nil array.detect { |each| each == element } != nil

요소가 있는 경우 true ish 값을 반환합니다.

include? 선호하는 방법입니다. rb_equal_opt/rb_equal 함수와 일치할 때 중단되는 내부적으로 C 언어 for 루프를 사용합니다. 반복되는 구성원 확인을 위한 집합을 생성하지 않는 한 훨씬 더 효율적일 수 없습니다.

 VALUE rb_ary_includes(VALUE ary, VALUE item) { long i; VALUE e; for (i=0; i<RARRAY_LEN(ary); i++) { e = RARRAY_AREF(ary, i); switch (rb_equal_opt(e, item)) { case Qundef: if (rb_equal(e, item)) return Qtrue; break; case Qtrue: return Qtrue; } } return Qfalse; }

member? Array 클래스에서 재정의되지 않고 문자 그대로 모든 요소를 열거 Enumerable 모듈의 최적화되지 않은 구현을 사용합니다.

 static VALUE member_i(RB_BLOCK_CALL_FUNC_ARGLIST(iter, args)) { struct MEMO *memo = MEMO_CAST(args); if (rb_equal(rb_enum_values_pack(argc, argv), memo->v1)) { MEMO_V2_SET(memo, Qtrue); rb_iter_break(); } return Qnil; } static VALUE enum_member(VALUE obj, VALUE val) { struct MEMO *memo = MEMO_NEW(val, Qfalse, 0); rb_block_call(obj, id_each, 0, 0, member_i, (VALUE)memo); return memo->v2; }

Ruby 코드로 변환하면 다음 작업이 수행됩니다.

 def member?(value) memo = [value, false, 0] each_with_object(memo) do |each, memo| if each == memo[0] memo[1] = true break end memo[1] end

둘 다 include? 그리고 member? 둘 다 예상 값의 첫 번째 발생에 대해 배열을 검색하기 때문에 O(n) 시간 복잡도를 갖습니다.

먼저 배열의 해시 표현을 생성해야 하는 비용으로 Set을 사용하여 O(1) 액세스 시간을 얻을 수 있습니다. 동일한 어레이에서 구성원 자격을 반복적으로 확인하는 경우 이 초기 투자 비용을 빠르게 회수할 수 있습니다. Set 은 C로 구현되지 않았지만 일반 Ruby 클래스로 기본 @hash 의 O(1) 액세스 시간이 이를 가치 있게 만듭니다.

다음은 Set 클래스의 구현입니다.

 module Enumerable def to_set(klass = Set, *args, &block) klass.new(self, *args, &block) end end class Set def initialize(enum = nil, &block) # :yields: o @hash ||= Hash.new enum.nil? and return if block do_with_enum(enum) { |o| add(block[o]) } else merge(enum) end end def merge(enum) if enum.instance_of?(self.class) @hash.update(enum.instance_variable_get(:@hash)) else do_with_enum(enum) { |o| add(o) } end self end def add(o) @hash[o] = true self end def include?(o) @hash.include?(o) end alias member? include? ... end

보시다시피 Set 클래스는 내부 @hash 인스턴스를 생성하고 모든 개체를 true Hash#include? 사용하여 구성원 자격을 확인합니다. 이는 Hash 클래스에서 O(1) 액세스 시간으로 구현됩니다.

다른 7가지 방법은 모두 덜 효율적이므로 논의하지 않겠습니다.

실제로 위에 나열된 11개 외에도 O(n) 복잡성을 가진 훨씬 더 많은 메서드가 있지만 첫 번째 일치에서 중단되지 않고 전체 배열을 스캔하기 때문에 나열하지 않기로 결정했습니다.

다음을 사용하지 마십시오.

 # bad examples array.grep(element).any? array.select { |each| each == element }.size > 0 ...

akuhn

여러 답변에서 Array#include? , 하지만 한 가지 중요한 주의 사항이 있습니다. 소스, 심지어 Array#include? 루핑을 수행합니다:

 rb_ary_includes(VALUE ary, VALUE item) { long i; for (i=0; i<RARRAY_LEN(ary); i++) { if (rb_equal(RARRAY_AREF(ary, i), item)) { return Qtrue; } } return Qfalse; }

반복하지 않고 단어 존재를 테스트하는 방법은 배열에 대한 시도를 구성하는 것입니다. 많은 시도 구현이 있습니다(google "ruby trie"). 이 예에서는 rambling-trie 를 사용합니다.

 a = %w/cat dog bird/ require 'rambling-trie' # if necessary, gem install rambling-trie trie = Rambling::Trie.create { |trie| a.each do |e| trie << e end }

Array#include? 와 동일한 구문 단순성을 사용 O(log n) 시간에 반복하지 않고 배열에 다양한 단어가 있는지 테스트할 준비가 되었습니다. , 하위 선형 Trie#include? :

 trie.include? 'bird' #=> true trie.include? 'duck' #=> false

Boris Stitnicky

반복하고 싶지 않다면 배열로 할 수 있는 방법이 없습니다. 대신 Set을 사용해야 합니다.

 require 'set' s = Set.new 100.times{|i| s << "foo#{i}"} s.include?("foo99") => true [1,2,3,4,5,6,7,8].to_set.include?(4) => true

집합은 내부적으로 해시처럼 작동하므로 Ruby는 이름에서 알 수 있듯이 키의 해시를 생성하고 각 해시가 메모리의 특정 지점을 가리키도록 메모리 맵을 생성하기 때문에 항목을 찾기 위해 컬렉션을 반복할 필요가 없습니다. 해시로 수행한 이전 예:

 fake_array = {} 100.times{|i| fake_array["foo#{i}"] = 1} fake_array.has_key?("foo99") => true

단점은 세트와 해시 키는 고유한 항목만 포함할 수 있으며 많은 항목을 추가하는 경우 Ruby는 더 큰 키 공간에 맞는 새 맵을 빌드하기 위해 특정 수의 항목 후에 전체를 다시 해시해야 합니다. 이에 대한 자세한 내용은 " MountainWest RubyConf 2014 - Nathan Long의 Big O in a Homemade Hash "를 시청하는 것이 좋습니다.

다음은 벤치마크입니다.

 require 'benchmark' require 'set' array = [] set = Set.new 10_000.times do |i| array << "foo#{i}" set << "foo#{i}" end Benchmark.bm do |x| x.report("array") { 10_000.times { array.include?("foo9999") } } x.report("set ") { 10_000.times { set.include?("foo9999") } } end

결과:

 user system total real array 7.020000 0.000000 7.020000 ( 7.031525) set 0.010000 0.000000 0.010000 ( 0.004816)

Kimmo Lehto

이를 수행하는 또 다른 방법은 Array#index 메서드를 사용하는 것입니다.

배열에서 요소가 처음 나타나는 인덱스를 반환합니다.

예를 들어:

 a = ['cat','dog','horse'] if a.index('dog') puts "dog exists in the array" end

index() 는 블록을 사용할 수도 있습니다.

예를 들어:

 a = ['cat','dog','horse'] puts a.index {|x| x.match /o/}

이것은 문자 'o'를 포함하는 배열의 첫 번째 단어의 인덱스를 반환합니다.


Zack Xu

재미있는 사실,

* case 표현식에서 배열 구성원을 확인할 수 있습니다.

 case element when *array ... else ... end

* 에 주목하십시오. 이것은 배열의 구성원을 확인합니다.

splat 연산자의 모든 일반적인 마술 동작이 적용되므로 예를 들어 array 이 실제로 배열이 아니라 단일 요소인 경우 해당 요소와 일치합니다.


akuhn

이를 수행하는 방법에는 여러 가지가 있습니다. 그 중 몇 가지는 다음과 같습니다.

 a = [1,2,3,4,5] 2.in? a #=> true 8.in? a #=> false a.member? 1 #=> true a.member? 8 #=> false

sumit

이것은 그것이 존재하는지 뿐만 아니라 그것이 몇 번이나 나타나는지 알려줄 것입니다:

 a = ['Cat', 'Dog', 'Bird'] a.count("Dog") #=> 1

user3245240

키에 대해 여러 번 확인해야 하는 경우 arrhash 로 변환하고 이제 O(1)을 확인합니다.

 arr = ['Cat', 'Dog', 'Bird'] hash = arr.map {|x| [x,true]}.to_h => {"Cat"=>true, "Dog"=>true, "Bird"=>true} hash["Dog"] => true hash["Insect"] => false

Hash#has_key의 성능은? 대 Array#include?

매개변수 해시#has_key? 배열#포함 

시간 복잡도 O(1) 연산 O(n) 연산 

액세스 유형 각 요소를 반복하는 경우 Hash[key]에 액세스합니다.
                        그 때까지 배열의 모든 값을 반환합니다.
                        Array에서 값을 찾으면 true가 반환됩니다.
                        해시#has_key? 전화
                        전화    

include? 사용하여 한 번 확인하려면? 괜찮습니다


aqfaridi

당신은 시도 할 수 있습니다:

예: Cat 및 Dog가 배열에 있는 경우:

 (['Cat','Dog','Bird'] & ['Cat','Dog'] ).size == 2 #or replace 2 with ['Cat','Dog].size

대신에:

 ['Cat','Dog','Bird'].member?('Cat') and ['Cat','Dog','Bird'].include?('Dog')

참고: member? 그리고 include? 동일합니다.

이것은 한 줄로 작업을 수행할 수 있습니다!


Daniel Antonio Nuñez Carhuayo

그만한 가치가 있기 때문에 Ruby 문서 는 이러한 종류의 질문에 대한 놀라운 리소스입니다.

또한 검색 중인 배열의 길이도 기록해 둡니다. include? 이 메서드는 O(n) 복잡성으로 선형 검색을 실행하며 배열의 크기에 따라 상당히 추악해질 수 있습니다.

큰(정렬된) 배열로 작업하는 경우 너무 어렵지 않고 최악의 경우 O(log n)인 이진 검색 알고리즘을 작성하는 것이 좋습니다.

또는 Ruby 2.0을 사용하는 경우 bsearch 활용할 수 있습니다.


davissp14

include? 사용하지 않으려면? 이것은 또한 작동합니다:

 ['cat','dog','horse'].select{ |x| x == 'dog' }.any?

xlembouras

이 방법은 어떻습니까?

 ['Cat', 'Dog', 'Bird'].index('Dog')

ajahongir

['Cat', 'Dog', 'Bird'].detect { |x| x == 'Dog'} => "Dog" !['Cat', 'Dog', 'Bird'].detect { |x| x == 'Dog'}.nil? => true

Rahul Patel

당신은이 작업을 수행하려는 경우 MiniTest의 단위 테스트, 당신은 사용할 수 있습니다 assert_includes . 예시:

 pets = ['Cat', 'Dog', 'Bird'] assert_includes(pets, 'Dog') # -> passes assert_includes(pets, 'Zebra') # -> fails

Jon Schneider

다른 방법이 있습니다.

[ :edit, :update, :create, :show ] 라고 가정하고, 아마도 전체 7개의 치명적/안식한 죄일 것 입니다.

그리고 어떤 문자열에서 유효한 조치를 당겨의 아이디어와 더 장난감 :

 "my brother would like me to update his profile"

그 다음에:

 [ :edit, :update, :create, :show ].select{|v| v if "my brother would like me to update his profile".downcase =~ /[,|.| |]#{v.to_s}[,|.| |]/}

walt_die

true 또는 false가 아닌 값을 반환하려면 다음을 사용하십시오.

 array.find{|x| x == 'Dog'}

목록에 있으면 'Dog'를 반환하고 그렇지 않으면 nil을 반환합니다.


gitb

include? 을 사용하지 않으려면? 먼저 요소를 배열로 래핑한 다음 래핑된 요소가 배열과 래핑된 요소의 교집합과 같은지 확인할 수 있습니다. 이것은 평등을 기반으로 하는 부울 값을 반환합니다.

 def in_array?(array, item) item = [item] unless item.is_a?(Array) item == array & item end

mgidea

나는 어떤 일을 하는 다양한 방법의 상대적 속도를 보기 위해 몇 가지 벤치마크를 실행하는 것이 항상 흥미롭다는 것을 알았습니다.

시작, 중간 또는 끝에서 배열 요소를 찾는 것은 모든 선형 검색에 영향을 미치지만 세트에 대한 검색에는 거의 영향을 미치지 않습니다.

배열을 세트로 변환하면 처리 시간이 단축되므로 배열에서 세트를 한 번 생성하거나 처음부터 세트로 시작하십시오.

다음은 벤치마크 코드입니다.

 # frozen_string_literal: true require 'fruity' require 'set' ARRAY = (1..20_000).to_a SET = ARRAY.to_set DIVIDER = '-' * 20 def array_include?(elem) ARRAY.include?(elem) end def array_member?(elem) ARRAY.member?(elem) end def array_index(elem) ARRAY.index(elem) >= 0 end def array_find_index(elem) ARRAY.find_index(elem) >= 0 end def array_index_each(elem) ARRAY.index { |each| each == elem } >= 0 end def array_find_index_each(elem) ARRAY.find_index { |each| each == elem } >= 0 end def array_any_each(elem) ARRAY.any? { |each| each == elem } end def array_find_each(elem) ARRAY.find { |each| each == elem } != nil end def array_detect_each(elem) ARRAY.detect { |each| each == elem } != nil end def set_include?(elem) SET.include?(elem) end def set_member?(elem) SET.member?(elem) end puts format('Ruby v.%s', RUBY_VERSION) { 'First' => ARRAY.first, 'Middle' => (ARRAY.size / 2).to_i, 'Last' => ARRAY.last }.each do |k, element| puts DIVIDER, k, DIVIDER compare do _array_include? { array_include?(element) } _array_member? { array_member?(element) } _array_index { array_index(element) } _array_find_index { array_find_index(element) } _array_index_each { array_index_each(element) } _array_find_index_each { array_find_index_each(element) } _array_any_each { array_any_each(element) } _array_find_each { array_find_each(element) } _array_detect_each { array_detect_each(element) } end end puts '', DIVIDER, 'Sets vs. Array.include?', DIVIDER { 'First' => ARRAY.first, 'Middle' => (ARRAY.size / 2).to_i, 'Last' => ARRAY.last }.each do |k, element| puts DIVIDER, k, DIVIDER compare do _array_include? { array_include?(element) } _set_include? { set_include?(element) } _set_member? { set_member?(element) } end end

내 Mac OS 랩톱에서 실행하면 다음과 같은 결과가 나타납니다.

 Ruby v.2.7.0 -------------------- First -------------------- Running each test 65536 times. Test will take about 5 seconds. _array_include? is similar to _array_index _array_index is similar to _array_find_index _array_find_index is faster than _array_any_each by 2x ± 1.0 _array_any_each is similar to _array_index_each _array_index_each is similar to _array_find_index_each _array_find_index_each is faster than _array_member? by 4x ± 1.0 _array_member? is faster than _array_detect_each by 2x ± 1.0 _array_detect_each is similar to _array_find_each -------------------- Middle -------------------- Running each test 32 times. Test will take about 2 seconds. _array_include? is similar to _array_find_index _array_find_index is similar to _array_index _array_index is faster than _array_member? by 2x ± 0.1 _array_member? is faster than _array_index_each by 2x ± 0.1 _array_index_each is similar to _array_find_index_each _array_find_index_each is similar to _array_any_each _array_any_each is faster than _array_detect_each by 30.000000000000004% ± 10.0% _array_detect_each is similar to _array_find_each -------------------- Last -------------------- Running each test 16 times. Test will take about 2 seconds. _array_include? is faster than _array_find_index by 10.000000000000009% ± 10.0% _array_find_index is similar to _array_index _array_index is faster than _array_member? by 3x ± 0.1 _array_member? is faster than _array_find_index_each by 2x ± 0.1 _array_find_index_each is similar to _array_index_each _array_index_each is similar to _array_any_each _array_any_each is faster than _array_detect_each by 30.000000000000004% ± 10.0% _array_detect_each is similar to _array_find_each -------------------- Sets vs. Array.include? -------------------- -------------------- First -------------------- Running each test 65536 times. Test will take about 1 second. _array_include? is similar to _set_include? _set_include? is similar to _set_member? -------------------- Middle -------------------- Running each test 65536 times. Test will take about 2 minutes. _set_member? is similar to _set_include? _set_include? is faster than _array_include? by 1400x ± 1000.0 -------------------- Last -------------------- Running each test 65536 times. Test will take about 4 minutes. _set_member? is similar to _set_include? _set_include? is faster than _array_include? by 3000x ± 1000.0

기본적으로 결과는 첫 번째 요소가 내가 원하는 요소라는 것을 보장할 수 없는 한 포함을 검색하려는 경우 모든 것에 대해 Set을 사용하라고 알려줍니다. 해시에 요소를 삽입할 때 약간의 오버헤드가 있지만 검색 시간이 훨씬 빨라서 고려하지 않아도 됩니다. 다시 말하지만, 검색이 필요하면 Array를 사용하지 말고 Set을 사용하십시오. (또는 해시.)

Array가 작을수록 Array 메서드가 더 빨리 실행되지만 작은 배열에서는 차이가 작을 수 있지만 여전히 따라가지 못합니다.

"First", "Middle" 및 "Last"는 검색되는 요소의 ARRAY first , size / 2last ARRAYSET 변수를 검색할 때 사용됩니다.

index 유형 테스트의 경우 테스트가 >= 0 > 0 과 비교하는 방법에 대해 약간의 변경이 있었습니다.

Fruity와 그 방법론에 대한 자세한 정보는 README 에서 확인할 수 있습니다.


Community Wiki

이 작업을 수행하는 또 다른 방법은 다음과 같습니다.

 arr = ['Cat', 'Dog', 'Bird'] e = 'Dog' present = arr.size != (arr - [e]).size

Wand Maker

배열에서 요소를 찾는 방법은 여러 가지가 있지만 가장 간단한 방법은 'in ?' 방법.

 example: arr = [1,2,3,4] number = 1 puts "yes #{number} is present in arr" if number.in? arr

Abhishek kumar

array = [ 'Cat', 'Dog', 'Bird' ] array.include?("Dog")

Matthew Maurice

출처 : http:www.stackoverflow.com/questions/1986386/how-to-check-if-a-value-exists-in-an-array-in-ruby

반응형