programing

루비의 배열에 값이 있는지 확인하는 방법

telebox 2023. 5. 17. 22:46
반응형

루비의 배열에 값이 있는지 확인하는 방법

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

배열을 반복하지 않고 배열에 존재하는지 확인하려면 어떻게 해야 합니까?값이 존재하는지, 그 이상은 없는지 간단하게 확인할 수 있는 방법이 있습니까?

다음을 찾고 있습니다.

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

방법이 있습니다.ActiveSupport(레일의 일부) v3.1 이후, @campeterson이 지적한 바와 같이. 레일즈에서, 만약 이 일즈내면, 또당이.require 'active_support'다음과 같이 쓸 수 있습니다.

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

OTOH는 .in 또는 연자또는#in?이전에 제안된 적이 있음에도 불구하고 루비 자체의 방법, 특히 루비 코어의 최고 노치 멤버인 엔도 유스케에 의해.

다른 사람들이 지적했듯이, 그 반대의 방법은 모두에게 존재합니다.Enumerable을 한 sArray,Hash,Set,Range:

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

배에많 값은있 경는모 예차값확인됩니다례로이든우이열예:(▁note다니확됩인▁in:O(n)), 상수 )이 될 해에대 조즉일정시한간는회한시즉시(간▁),,일▁while한정▁be▁that▁constant▁will▁(▁for,O(1)예를 들어 배열이 일정한 경우에는 집합을 대신 사용하는 것이 좋습니다.예:

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? 에.Set에 해당하는 제서호출것는약보하다에 3.5빠더다에서 하는 약 3 더 .Array(요소를 찾을 수 없는 경우).

마지막 마무리 노트: 사용 시 주의해야 합니다.include?에서.Range세부사항이 있으므로 문서를 참조하여 ...와 비교해 보십시오.

해라

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

블록 단위로 확인하고 싶다면, 당신은 시도할 수 있습니다.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  

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

"array에 루비로 표시된 항목이 있는지 평가"에서 영감을 얻었습니다.

사용하다Enumerable#include:

a = %w/Cat Dog Bird/

a.include? 'Dog'

또는 여러 테스트를 1수행하면 루프를 제거할 수 있습니다(심지어include?has)를 사용하여 O(n)에서 O(1)로 이동합니다.

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


저는 이것이 명백하지만 반대를 피하기를 바랍니다. 네, 단지 몇 가지 검색을 위해, 해시[]와 전치 작업이 프로필을 지배하고 각각 O(n)입니다.

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

은 호하는것은선입니다.include?또는 반복적인 액세스를 위해 세트를 만든 다음 호출합니다.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

그들은 모두 a를 반환합니다.true요소가 있는 경우 iss 값.

include?선호하는 방법입니다.은 C 인 C 어니용사다를 사용합니다.for와 할 때 rb_equal_opt/rb_equal인 구성원 검사에 일 수 .반복적인 구성원 자격 검사에 대한 집합을 만들지 않는 한 효율성이 훨씬 더 높아질 수 없습니다.

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의 O은 Ruby 래클구며현되고, 전인스 O(1) 액세시입니다.@hash이것을 가치 있게 만듭니다.

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 으로 Set을 합니다.@hash 모든 를 인턴스(")에 .true 런그 다음회확인다니합격자을원hip▁members▁using▁and다를 사용하여 멤버십을 확인합니다.Hash#include?해시 클래스에서 O(1) 액세스 시간으로 구현됩니다.

나머지 7가지 방법은 모두 효율성이 떨어지므로 논의하지 않겠습니다.

실제로 위에 나열된 11개 이상의 O(n) 복잡도를 가진 메소드가 더 있지만, 첫 번째 매치에서 깨지는 것이 아니라 전체 어레이를 스캔하기 때문에 나열하지 않기로 결정했습니다.

사용 안 함:

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

몇 가지 대답은 다음과 같습니다.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;
}

루프 없이 단어 존재를 테스트하는 방법은 배열에 대한 트라이를 구성하는 것입니다.많은 시행착오가 있습니다(구글 "roby 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 }

하지 않고 .O(log n)시간, 동한통과 같은 을 가지고 .Array#include? 선형 하선형사용위▁sub용▁usingTrie#include?:

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

루프를 수행하지 않으려면 어레이를 사용할 수 없습니다.대신 집합을 사용해야 합니다.

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는 이름에서 알 수 있듯이 키의 해시를 생성하고 각 해시가 메모리의 특정 지점을 가리키도록 메모리 맵을 만들기 때문에 Hashes와 같이 내부적으로 작동하므로 항목을 찾기 위해 컬렉션을 반복할 필요가 없습니다.해시를 사용한 이전 예제:

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

단점은 Sets와 Hash 키는 고유한 항목만 포함할 수 있고 항목을 많이 추가하면 Ruby가 더 큰 키 공간에 맞는 새 맵을 구축하기 위해 특정 항목 이후에 전체를 다시 해시해야 한다는 것입니다.이에 대한 자세한 내용은 "Mountain West RubyConf 2014 - Nathan Long의 집에서 만든 해시의 빅오"를 보는 것을 추천합니다.

다음은 벤치마크입니다.

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)

하는: 이를위또방다같음습다니과은법다른한▁the다같▁this습니▁use다음과▁is를 사용합니다.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' 문자가 포함된 배열의 첫 번째 단어 색인이 반환됩니다.

체크 있음

사용하다include?

예:

arr = [1, 2, 3]
arr.include?(1) -> true
arr.include?(4) -> false

체크가 존재하지 않습니다.

사용하다exclude?

예:

arr = %w(vietnam china japan)
arr.exclude?('usa') -> true
arr.exclude?('china') -> false

재미있는 사실은,

사용할 수 있습니다.*에서 구자검면려사하에서 합니다.case표현.

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

것을 보세요.*when 절에서는 배열의 구성원 자격을 확인합니다.

스플랫 연산자의 모든 일반적인 마법 동작이 적용되므로, 예를 들어,array실제로는 배열이 아니지만 단일 요소와 일치합니다.

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

a = [1,2,3,4,5]

2.in? a  #=> true

8.in? a #=> false

a.member? 1 #=> true

a.member? 8 #=> false

이 메시지는 해당 메시지가 존재할 뿐만 아니라 다음과 같이 표시되는 횟수도 알려줍니다.

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

시도할 수 있습니다.

예: 배열에 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?똑같습니다.

이것은 한 줄로 일을 할 수 있습니다!

번 해야 할 에는 변환을 수행합니다.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# 포함 여부와 비교?

매개 변수 Hash#has_key?배열 # 포함
시간 복잡도 O(1) 연산 O(n) 연산
액세스 유형 각 요소를 통해 반복되는 경우 해시[key]에 액세스합니다.배열의 모든 값을 반환합니다.true는 어레이에서 값을 찾습니다.Hash #has_key? 호출불러

단일 시간 검사의 경우 다음을 사용합니다.include?

루비 문서는 이런 종류의 질문들을 위한 놀라운 자료입니다.

검색 중인 배열의 길이도 기록해 두겠습니다.include?메소드는 배열의 크기에 따라 상당히 추해질 수 있는 O(n) 복잡도로 선형 검색을 실행합니다.

만약 당신이 큰 (정렬된) 배열로 작업하고 있다면, 저는 너무 어렵지 않고 최악의 경우 O(log n)인 이진 검색 알고리즘을 작성하는 것을 고려할 것입니다.

또는 Ruby 2.0을 사용하는 경우에는bsearch.

가 사하지않면을 사용하지 .include?이 기능도 작동합니다.

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

이쪽은 어떻습니까?

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

MiniTest 장치 테스트에서 이 작업을 수행하려는 경우 를 사용할 수 있습니다. 예:

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

다른 방법이 있습니다.

배열이 다음과 같다고 가정합니다.[ :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}[,|.| |]/}

저는 항상 벤치마크를 실행하여 다양한 방법의 상대적인 속도를 확인하는 것이 흥미롭다고 생각합니다.

시작, 중간 또는 끝에서 배열 요소를 찾으면 선형 검색에는 영향을 미치지만 집합에 대한 검색에는 거의 영향을 주지 않습니다.

배열을 집합으로 변환하면 처리 시간에 문제가 발생하므로 집합을 배열에서 한 번 만들거나 처음부터 집합으로 시작합니다.

벤치마크 코드는 다음과 같습니다.

# 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

기본적으로 결과는 첫 번째 요소가 원하는 요소인지 확인할 수 없는 경우 포함 항목을 검색하려면 모든 항목에 집합을 사용하도록 지시합니다. 이는 가능성이 매우 낮습니다.해시에 요소를 삽입할 때 약간의 오버헤드가 발생하지만 검색 시간이 너무 빠르기 때문에 고려 사항이 될 수 없습니다.다시 말하지만, 검색이 필요하다면 배열을 사용하지 말고 집합을 사용하십시오. (또는 해시)

어레이가 작을수록 어레이 메소드가 더 빨리 실행되지만, 작은 어레이에서는 차이가 작을 수 있지만 이를 따라가지는 못합니다.

"첫 번째 "은 "첫번째간", "중막마은", "지및니나다다사냅타음"의 사용을 반영합니다first,size / 2그리고.last위해서ARRAY검색 중인 요소에 대한.는 해당요검시사다니됩용색는소를 할 때 입니다.ARRAY그리고.SET변수

비교 중인 방법에 대해 약간의 변경이 있었습니다.> 0왜냐하면 그 시험은 그래야 하기 때문입니다.>= 0위해서index활자 시험

Fruity 및 방법론에 대한 자세한 내용은 README에서 확인할 수 있습니다.

배열에서 요소를 찾는 방법은 많지만 가장 간단한 방법은 'in?' 방법입니다.

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

true 또는 false가 아닌 값을 반환하려면 다음을 사용합니다.

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

목록에 'Dog'가 있으면 반환되고, 없으면 0이 됩니다.

사용하지 않으려는 경우include?먼저 요소를 배열로 래핑한 다음 래핑된 요소가 배열과 래핑된 요소의 교차점과 동일한지 확인할 수 있습니다.동일성을 기준으로 부울 값을 반환합니다.

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

이를 위한 또 다른 방법은 다음과 같습니다.

arr = ['Cat', 'Dog', 'Bird']
e = 'Dog'

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

아래로 시도해 보십시오.

(['Cat', 'Dog', 'Bird'] & ['Dog']).any?

언급URL : https://stackoverflow.com/questions/1986386/how-to-check-if-a-value-exists-in-an-array-in-ruby

반응형