अगर रुबी में किसी सरणी में मान मौजूद है, तो कैसे जांचें


1314

मेरे पास एक मूल्य 'Dog'और एक सरणी है ['Cat', 'Dog', 'Bird']

यदि मैं इसके माध्यम से बिना लूपिंग के सरणी में मौजूद है, तो मैं कैसे जांचूं? क्या जाँच का एक आसान तरीका है यदि मूल्य मौजूद है, और कुछ नहीं?


5
.include का उपयोग करें विधि । यह एक बूलियन देता है जो आप चाहते हैं। आपके मामले में बस टाइप करें: ['कैट', 'डॉग', 'बर्ड']। ('डॉग') को शामिल करें और यह बूलियन सच लौटना चाहिए।
Jwan622

शामिल न करें ? विधि यदि आप सरणी में उपस्थित होने के लिए अलग-अलग मूल्य के गुणकों को बार-बार जांचना चाहते हैं या शामिल नहीं हैं? हर बार हर बार खोज करने के लिए O (n) ऑपरेशन को ले कर सरणी पर पुनरावृत्ति होगी, इसके बजाय एक हैश करें hash = arr.map {|x| [x,true]}.to_h, अब जांचें कि क्या hash.has_key? 'Dog' सही है या नहीं
aqfaridi

3
आप वास्तव में इसे पूरी तरह से "इसके माध्यम से लूपिंग के बिना" नहीं कर सकते। यह तार्किक रूप से असंभव है, कंप्यूटर अभी यह सुनिश्चित करने के लिए नहीं जान सकता है कि क्या सरणी में तत्वों के माध्यम से लूपिंग के बिना तत्व शामिल है या नहीं, यह जांचने के लिए कि उनमें से कोई एक है जिसे वह खोज रहा है। जब तक वह खाली न हो, अवश्य। तब मुझे लगता है कि आपको एक लूप की आवश्यकता नहीं है।
टिम एम।

ऐरे और सेट में एक तत्व को खोजने के लिए विभिन्न तरीकों के अंतर के परीक्षणों के लिए नीचे दिए गए बेंचमार्क देखें। stackoverflow.com/a/60404934/128421
टिन मैन

जवाबों:


1944

आप देख रहे हैं include?:

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

73
वैकल्पिक वाक्य रचना:%w(Cat Dog Bird).include? 'Dog'
scarver2

184
कभी-कभी मेरी इच्छा थी कि इसमें "समाहित" शामिल न हो। मैं हमेशा इसे शामिल करता हूं।
हेनले चिउ

19
मुझे अभी ध्यान दें कि आंतरिक रूप से, #include?अभी भी लूपिंग का प्रदर्शन करता है। कोडर को लूप को स्पष्ट रूप से लिखने से बचाया जाता है, हालांकि। मैंने एक उत्तर जोड़ा है जो बिना लूपिंग के वास्तव में कार्य करता है।
बोरिस स्टिटनिक

8
@ हेनलीच्यू I जिसे यह कहा जाता था[ 'Dog', 'Bird', 'Cat' ].has? 'Dog'

4
@AlfonsoVergara हाँ, सरणी के लिए कोई भी समाधान आंतरिक रूप से किसी प्रकार का लूपिंग करना चाहिए; लूपिंग के बिना किसी सरणी की सदस्यता के लिए परीक्षण करने का कोई तरीका नहीं है। यदि आप आंतरिक रूप से भी कोई लूपिंग नहीं करना चाहते हैं, तो आपको एक अलग डेटा संरचना का उपयोग करने की आवश्यकता होती है, जैसे कि एक सही हैश तालिका जिसमें सभी आकार की चाबियां होती हैं। यह देखते हुए कि आंतरिक रूप से लूपिंग के बिना किसी सरणी में सदस्यता के लिए परीक्षण करने का कोई तरीका नहीं है, मैंने प्रश्न का अर्थ "स्पष्ट रूप से स्वयं को लूप लिखने के बिना" दिया
ब्रायन कैंपबेल

250

एक in?विधि हैActiveSupportV3.1 के बाद से (Rails का हिस्सा) में है , जैसा कि @campaterson द्वारा बताया गया है। तो रेल के भीतर, या यदि आप require 'active_support', आप लिख सकते हैं:

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

OTOH, वहाँ नहीं है in#in? रूबी में ही ऑपरेटर या विधि है, भले ही यह पहले प्रस्तावित किया गया हो, विशेष रूप से रूबी-कोर के शीर्ष पायदान सदस्य युसुके एंडोह द्वारा

के रूप में दूसरों के द्वारा कहा, रिवर्स विधि include?मौजूद है, सभी के लिए Enumerableसहित Array, Hash, Set,Range :

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

ध्यान दें कि यदि आपके सरणी में कई मान हैं, तो वे सभी एक के बाद एक (यानी O(n)) चेक किए जाएंगे , जबकि हैश के लिए खोज निरंतर समय होगा (अर्थात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?10 तत्व पर कॉल Setकरना लगभग 3.5x तेज है इसे समकक्ष पर कॉल करना Array(यदि तत्व नहीं मिला है)।

एक अंतिम समापन नोट: include?एक का उपयोग करते समय सावधान रहें Range, सूक्ष्मताएं हैं, इसलिए डॉक्टर को देखें और साथ तुलना करें cover?...


2
जबकि रूबी इसमें शामिल नहीं है #in?, यदि आप रेल का उपयोग कर रहे हैं, तो यह उपलब्ध है। api.rubyonrails.org/classes/Object.html#method-i-in-3F (मुझे पता है कि यह एक रूबी है, न कि एक रेल सवाल है, लेकिन यह किसी को भी #in?रेल में उपयोग करने की तलाश में मदद कर सकता है । ऐसा लगता है जैसे रेल में जोड़ा गया था। 3.1 एपिडॉक.com
rails/

166

प्रयत्न

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

यह पुराना वाक्य-विन्यास है, ^ ^ ^ @ brian का जवाब
jahrichie

62
@jahrichie क्या आप वास्तव में इस जवाब में "पुराने वाक्यविन्यास" पर विचार करते हैं, वैकल्पिक कोष्ठक?
डेनिस

3
मैं मानता हूं @ डेनिस, यह अधिक पुराना नहीं है, कोष्ठक वैकल्पिक हैं और अधिकांश मामलों में एक अच्छा व्यवहार .... उदाहरण के लिए यदि वाक्य में एक पंक्ति में कोष्ठक के बिना शामिल करने का प्रयास करें, तो मेरा क्या मतलब है कि आपके मामले पर निर्भर करता है कोष्ठक का उपयोग करना चाहिए या नहीं ("पुराने" रूबी
सिंटैक्स

यह एकमात्र वाक्यविन्यास है जो मुझे एक टर्नरी ऑपरेशन के भीतर काम करने के लिए मिल सकता है।
माइकल कैमरून

49

उपयोग करें Enumerable#include:

a = %w/Cat Dog Bird/

a.include? 'Dog'

या, यदि कई परीक्षण किए जाते हैं, तो 1 आप लूप से छुटकारा पा सकते हैं (वह भी include?है) और ओ (एन) से ओ (1) के साथ जाएं:

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


1. मुझे उम्मीद है कि यह स्पष्ट है, लेकिन आपत्तियों को दूर करने के लिए: हाँ, बस कुछ लुकअप के लिए, हैश [] और ट्रांसपोज़ ऑप्स प्रोफाइल पर हावी हैं और प्रत्येक O (n) स्वयं हैं।


48

यदि आप किसी ब्लॉक द्वारा जाँच करना चाहते हैं, तो आप कोशिश कर सकते हैं 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  

अधिक जानकारी के लिए Enumerable देखें ।

मेरी प्रेरणा से आया है " मूल्यांकन अगर सरणी रूबी में किसी भी आइटम है "


1
बहुत उपयोगी है अगर आप किसी भी / सभी स्ट्रिंग की जांच करना चाहते हैं, तो एक और स्ट्रिंग / निरंतर में शामिल किया गया है
थिंककल

43

एक सरणी में तत्वों को खोजने के लिए रूबी के पास ग्यारह तरीके हैं।

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

वे सभी एक लौट आए trueयदि तत्व मौजूद है तो ईश मान ।

include?पसंदीदा तरीका है। यह 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;
}

रूबी कोड में अनुवादित यह निम्न के बारे में करता है:

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 (1) एक्सेस समय प्राप्त करने के लिए एक सेट का उपयोग कर सकते हैं। यदि आप एक ही सरणी पर बार-बार सदस्यता की जांच करते हैं तो यह प्रारंभिक निवेश जल्दी भुगतान कर सकता है। Setसी में लागू नहीं है, लेकिन सादे रूबी वर्ग के रूप में, अभी भी अंतर्निहित का ओ (1) पहुंच समय है@hash इस लायक बनाता है।

यहाँ सेट वर्ग का कार्यान्वयन है:

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

जैसा कि आप देख सकते हैं सेट क्लास बस एक आंतरिक @hashउदाहरण बनाता है , सभी वस्तुओं को मैप trueकरता है और फिर सदस्यता का उपयोग करके जांच करता हैHash#include? करता है, जिसे हैश क्लास में ओ (1) एक्सेस समय के साथ कार्यान्वित किया जाता है।

मैं अन्य सात विधियों पर चर्चा नहीं करूंगा क्योंकि वे सभी कम कुशल हैं।

उपरोक्त सूचीबद्ध 11 से परे ओ (एन) जटिलता के साथ वास्तव में और भी अधिक विधियां हैं, लेकिन मैंने उन्हें सूचीबद्ध नहीं करने का फैसला किया क्योंकि वे पहले मैच में तोड़ने के बजाय पूरे सरणी को स्कैन करते हैं।

इनका उपयोग न करें:

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

कैसे कहने के लिए कि रूबी कुछ भी करने के लिए 11 तरीके हैं! आपके अलावा कोई भी यह नहीं कहता है कि कोई व्यक्ति आपको इंगित करेगा कि आप # 12, फिर # 13, और इसी तरह से चूक गए। अपनी बात कहने के लिए मैं अन्य तरीकों का सुझाव दूंगा, लेकिन पहले मुझे उन 11तरीकों पर सवाल उठाने दीजिए जो आपने बताए हैं। सबसे पहले, आप शायद ही भरोसा कर सकते हैं indexऔर find_index(या findऔर detect) अलग तरीके के रूप में, के रूप में वे एक ही विधि के लिए सिर्फ अलग अलग नाम हैं। दूसरे, सभी भाव जो समाप्त होते > 0हैं वे गलत हैं, जो मुझे यकीन है कि एक निरीक्षण था। (
प्रतियोगिता

... arr.index(e), उदाहरण के लिए, 0यदि रिटर्न arr[0] == e। यदि आप मौजूद नहीं हैं तो आपको arr.index(e)रिटर्न याद होगा । इस्तेमाल किया जा सकता है, लेकिन, अगर एक के लिए खोज कर रहा है में । (उसी समस्या के साथ , जो सूचीबद्ध नहीं है।) सरणी को सेट में परिवर्तित करना और फिर सेट विधियों को नियोजित करना थोड़ा खिंचाव है। फिर हैश (सरणी और मनमाने मूल्यों से कुंजियों के साथ) में परिवर्तित क्यों नहीं किया जाता है, फिर हैश विधियों का उपयोग करें? यहां तक ​​कि अगर किसी सेट में कनवर्ट करना ठीक है, तो अन्य सेट विधियां हैं जिनका उपयोग किया जा सकता है, जैसे कि । (cont।)nileindexnilarrrindex!arr.to_set.add?(e)
Cary Svelveland

... जैसा कि वादा किया था, यहाँ हैं कुछ और तरीकों कि इस्तेमाल किया जा सकता है: arr.count(e) > 0, arr != arr.dup.delete(e) , arr != arr - [e]और arr & [e] == [e]। एक भी काम कर सकता है selectऔर reject
कैरी स्वेवेलैंड

मैं एक सेट का उपयोग करने की अत्यधिक सलाह दूंगा यदि मानदंड यह है कि कोई डुप्लिकेट की अनुमति नहीं है, और यह जानना कि क्या कोई विशेष तत्व सूची में मौजूद है। सेट बहुत तेज़ है। खोज की आवश्यकता होने पर वास्तव में उपयोग नहीं किया जाना चाहिए; वे बेहतर तरीके से एक कतार के रूप में उपयोग किए जाते हैं जहां चीजें अस्थायी रूप से संग्रहीत की जाती हैं ताकि ऑर्डर में संसाधित किया जा सके। हैश और सेट देखने के लिए बेहतर है कि क्या कुछ मौजूद है।
टिन मैन

30

कई उत्तर बताते हैं 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;
}

लूपिंग के बिना शब्द उपस्थिति का परीक्षण करने का तरीका आपके सरणी के लिए एक त्रि का निर्माण करके है । वहाँ कई trie कार्यान्वयन वहाँ हैं (गूगल "रूबी 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?sublinear का उपयोग कर, Trie#include?:

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

8
a.each do ... endउम्म ... यकीन नहीं है कि कैसे एक पाश नहीं है
Doorknob

27
ध्यान दें कि इसमें वास्तव में एक लूप शामिल है; O (1) में कुछ भी शामिल नहीं है। यह सिर्फ इनपुट स्ट्रिंग के पात्रों पर एक लूप होता है। Set#include?उन लोगों के लिए पहले से उल्लेख किए गए उत्तर पर भी ध्यान दें जो दक्षता के बारे में चिंतित हैं; तार के बजाय प्रतीकों का उपयोग करने के साथ युग्मित, यह ओ (1) औसत मामला हो सकता है (यदि आप तार का उपयोग करते हैं, तो बस हैश की गणना हे (एन) है जहां n स्ट्रिंग की लंबाई है)। या यदि आप तीसरे पक्ष के पुस्तकालयों का उपयोग करना चाहते हैं, तो आप एक सही हैश का उपयोग कर सकते हैं जो ओ (1) सबसे खराब स्थिति है।
ब्रायन कैंपबेल

4
AFAIK, Setअपने सदस्यों को अनुक्रमित करने के लिए हैश का उपयोग करता है, इसलिए वास्तव में हैशिंग के लिए एक अच्छी तरह से वितरित (अधिक विशेष रूप से हे (इनपुट-आकार) और हे (लॉग / एन / बकेट-संख्या) के लिए जटिलता ओ (1) का Set#include? होना चाहिएSet ) खोज)
उड़ी अगासी

11
तीनों को बनाने और बनाए रखने की लागत बस उतनी ही है। यदि आप सरणी पर कई खोज अभियान कर रहे हैं, तो एक ट्राइ को पॉप करने और बनाए रखने की स्मृति और समय की लागत इसके लायक है, लेकिन एकल, या यहां तक ​​कि सैकड़ों या हजारों चेक के लिए, ओ (एन) पूरी तरह से उपयुक्त है। एक अन्य विकल्प जिसमें निर्भरता को जोड़ने की आवश्यकता नहीं होती है, वह सरणी को क्रमबद्ध करने या उसे क्रमबद्ध क्रम में बनाए रखने के लिए होगा, जिसमें शामिल होने की जांच के लिए एक द्विआधारी खोज ओ (lg n) ऑपरेशन का उपयोग किया जा सकता है।
बोल रहा हूं

1
@speakingcode, आप व्यावहारिक दृष्टिकोण से सही हो सकता है। लेकिन ओपी "जाँचता है कि क्या मूल्य मौजूद है, अधिक कुछ नहीं, बिना लूपिंग के"। जब मैंने यह उत्तर लिखा था, तो यहां कई व्यावहारिक समाधान थे, लेकिन कोई भी वास्तव में पूछने वाले की शाब्दिक आवश्यकता को पूरा नहीं करेगा। आपका अवलोकन कि BSTs कोशिशों से संबंधित है, सही है, लेकिन स्ट्रिंग्स के लिए, trie नौकरी के लिए सही उपकरण है, यहां तक ​​कि विकिपीडिया भी इसे बहुत जानता है । एक अच्छी तरह से लागू तिकड़ी के निर्माण और रखरखाव की जटिलता आश्चर्यजनक रूप से अनुकूल है।
बोरिस स्टिटनिक

18

यदि आप लूप नहीं करना चाहते हैं, तो एरे के साथ ऐसा करने का कोई तरीका नहीं है। आपको इसके बजाय सेट का उपयोग करना चाहिए।

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

आंतरिक रूप से हैश की तरह काम करता है, इसलिए रूबी को आइटम खोजने के लिए संग्रह के माध्यम से लूप करने की आवश्यकता नहीं है, क्योंकि जैसा कि नाम से पता चलता है, यह कुंजी का हैश उत्पन्न करता है और मेमोरी मैप बनाता है ताकि प्रत्येक हैश मेमोरी में एक निश्चित बिंदु पर इंगित हो। पिछला उदाहरण हैश के साथ किया गया:

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

नकारात्मक पक्ष यह है कि सेट्स और हैश कीज़ में केवल अनन्य आइटम शामिल हो सकते हैं और यदि आप बहुत सारे आइटम जोड़ते हैं, तो रूबी को एक नया नक्शा बनाने के लिए कुछ वस्तुओं की निश्चित संख्या के बाद पूरी चीज़ को फिर से गर्म करना होगा जो एक बड़े कीस्पेस पर सूट करता है। इसके बारे में अधिक जानकारी के लिए, मैं आपको " माउंटेनवेस्ट रूबीकॉन्फ़ 2014 " देखने की सलाह देता हूं - नाथन लॉन्ग द्वारा होममेड हैश में बिग ओ

यहाँ एक बेंचमार्क है:

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)

यदि आप डिटेक्ट का उपयोग करते हैं, तो आप कम से कम लूपिंग को कम कर सकते हैं। पहले आइटम 'डिटेक्ट' (रुका हुआ सच का मूल्यांकन करता है के लिए पारित ब्लॉक) पर पता लगना बंद हो जाएगा। इसके अलावा, आप यह बता सकते हैं कि यदि कुछ भी पता नहीं चला है तो आप क्या कर सकते हैं (आप लैम्ब्डा में पास कर सकते हैं)।
अनेन जुव

1
@aenw include?पहली हिट पर नहीं रुकता है ?
किममो लेह्टो

आप बिल्कुल सही कह रहे है। मुझे पता लगाने के लिए उपयोग किया जाता है कि मैं इसमें शामिल होने के बारे में भूल गया था। आपकी टिप्पणी के लिए धन्यवाद - यह सुनिश्चित किया कि मैंने अपने ज्ञान को ताज़ा किया।
एईएन

include?पहली हिट पर रुक जाता है लेकिन अगर वह हिट सूची के अंत में है .... किसी भी समाधान जो भंडारण के लिए एक सरणी पर निर्भर करता है, तो प्रदर्शन में गिरावट होती है क्योंकि सूची बढ़ती है, खासकर जब एक तत्व को खोजने के अंत में। सूची। हैश और सेट में वह समस्या नहीं है, न ही एक आदेशित सूची और एक द्विआधारी-खोज होगी।
टिन मैन

यह बहुत ज्यादा है कि यह उत्तर पहले के बारे में क्या था :)
किममो लेहटो

17

ऐसा करने का यह एक और तरीका है: 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/}

यह उस सरणी के पहले शब्द का सूचकांक देता है जिसमें 'ओ' अक्षर होता है।


indexअभी भी सरणी पर पुनरावृत्त होता है, यह सिर्फ तत्व का मान लौटाता है।
टिन मैन

13

मजेदार तथ्य,

आप एक्सप्रेशन *में एरे सदस्यता को चेक करने के लिए उपयोग कर सकते हैं case

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

*जब उपवाक्य में थोड़ा ध्यान दें , यह सरणी में सदस्यता के लिए जाँच करता है।

स्पैट ऑपरेटर के सभी सामान्य जादू व्यवहार लागू होते हैं, इसलिए उदाहरण के लिए यदि arrayवास्तव में एक सरणी नहीं है, लेकिन यह एक तत्व है जो उस तत्व से मेल खाएगा।


जानकार अच्छा लगा..!
कैरी स्वेवेलैंड

यह एक केस स्टेटमेंट में पहली धीमी जांच होगी, इसलिए मैं इसे अंतिम whenसंभव तरीके से उपयोग करूंगा ताकि अन्य, तेज जांच हो, जल्दी से खरपतवार निकल जाए।
टिन मैन

9

इसे पूरा करने के कई तरीके हैं। उनमें से कुछ इस प्रकार हैं:

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

2.in? a  #=> true

8.in? a #=> false

a.member? 1 #=> true

a.member? 8 #=> false

6
ध्यान दें कि Object#in?केवल रेल (यानी ActiveSupport) v3.1 + में जोड़ा गया था । यह कोर रूबी में उपलब्ध नहीं है।
टॉम लॉर्ड

5

यदि आपको किसी भी कुंजी के लिए कई गुना गुणा करने की आवश्यकता है, तो कन्वर्ट arrकरें hash, और अब 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

हैश # has_key का प्रदर्शन ? बनाम एरे # शामिल हैं?

पैरामीटर हैश # has_key? सरणी # शामिल

समय जटिलता ओ (1) ऑपरेशन ओ (एन) ऑपरेशन 

एक्सेस टाइप एक्सेस हैश [कुंजी] यदि यह प्रत्येक तत्व के माध्यम से इरेट करता है
                        तब तक सरणी के किसी भी मूल्य को वापस करता है
                        सही ऐरे में मान पाता है
                        हैश # has_key? कॉल
                        कॉल    

एकल समय के लिए चेक का उपयोग include?ठीक है


क्या आप अभी भी इसे हैश में बदलने के लिए सरणी के माध्यम से लूपिंग नहीं कर रहे हैं?
क्रिसटॉकोब

2
हां, मैंने किया था, लेकिन अब मेरे पास यह जांचने के लिए पूर्व-संकलित उत्तर है कि कोई तत्व सरणी में मौजूद है या नहीं। अब, अगली बार जब मैं दूसरे शब्द की खोज करूँगा, तो यह क्वेरी के लिए O (1) लेगा, हालाँकि, पूर्व संगणना O (n) लेगी। वास्तव में मैंने शामिल किया है? मेरे आवेदन में लूप के अंदर यह जांचने के लिए कि कोई विशेष तत्व सरणी में मौजूद है या नहीं, यह प्रदर्शन को बर्बाद करता है, यह रूबी-
प्रोफ में जांचा

1
.... लेकिन O (n) स्थान और भी, नहीं, यह O (n) समय है, क्योंकि @ chris72205 सही रूप में इंगित करता है, आपको पहले अपने सरणी के माध्यम से पुनरावृत्त करना होगा। O (1) + O (n) = O (n)। तो वास्तव में, यह तरीका शामिल से भी बदतर है?
रामबेटिनो

यार मैं सिर्फ कह रहा था कि लूप के अंदर शामिल न करें, सिंगल टाइम चेक के लिए शामिल करना ठीक है। तो कृपया पहले उपयोग के मामले को पढ़ें, इसके बेहतर यदि आपको लूप के अंदर कई बार जांच करने की आवश्यकता है।
अक्फ़ारिदी

किसी सरणी को हैश में परिवर्तित करना महंगा है, लेकिन खोज के लिए एक सरणी का उपयोग करना गलत संरचना है। आदेश पंक्ति के रूप में बेहतर हैं जहां आदेश महत्वपूर्ण हो सकते हैं; समावेशन / अस्तित्व / विशिष्टता महत्वपूर्ण होने पर हैश और सेट बेहतर होते हैं। सही कंटेनर से शुरू करें और समस्या मूट है।
टिन मैन

4

यह आपको बताएगा कि न केवल यह मौजूद है बल्कि यह भी कि यह कितनी बार दिखाई देता है:

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

12
इसका उपयोग करने में कोई समझदारी नहीं है जब तक आप जानना नहीं चाहते कि यह कितनी बार प्रकट होता है, हालांकि, .any?जैसे ही यह पहला मिलान तत्व पाता है, .countयह हमेशा पूरे सरणी को संसाधित करेगा।
ज़ाज

हालांकि यह तकनीकी रूप से बताएगा कि क्या कुछ मौजूद है, अगर आप गति के बारे में परवाह करते हैं तो यह सही तरीका नहीं है।
टिन मैन

4

इस लायक के लिए, रूबी डॉक्स इस प्रकार के प्रश्नों के लिए एक अद्भुत संसाधन हैं।

मैं उस सरणी की लंबाई पर भी ध्यान दूंगा जिसे आप खोज रहे हैं। include?विधि के साथ हे (एन) जटिलता एक रेखीय खोज जो सरणी के आकार के आधार सुंदर बदसूरत प्राप्त कर सकते हैं चलेंगे।

यदि आप एक बड़े (सॉर्ट किए गए) सरणी के साथ काम कर रहे हैं, तो मैं एक द्विआधारी खोज एल्गोरिथ्म लिखने पर विचार करूंगा जो बहुत मुश्किल नहीं होना चाहिए और ओ (लॉग एन) का सबसे खराब मामला है।

या यदि आप रूबी 2.0 का उपयोग कर रहे हैं, तो आप इसका लाभ उठा सकते हैं bsearch


3
एक द्विआधारी खोज मानती है कि सरणी को सॉर्ट किया गया है (या किसी रूप में ऑर्डर किया गया है) जो बड़े सरणियों के लिए महंगा हो सकता है, जो अक्सर लाभ को नकारता है।
टिन मैन

एक द्विआधारी खोज के लिए सभी जोड़े तत्वों की तुलना करने की आवश्यकता होती है <=>, जो हमेशा ऐसा नहीं होता है। उदाहरण के लिए मान लीजिए, सरणी के तत्व हैश थे।
कैरी स्वेवेलैंड

1
@CarySwoveland यह कम या ज्यादा निहित होना चाहिए कि एक क्रमबद्ध सरणी के भीतर तत्व तुलनीय हैं।
davissp14

4

तुम कोशिश कर सकते हो:

उदाहरण: यदि बिल्ली और कुत्ता सरणी में मौजूद हैं:

(['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?समान हैं।

यह काम एक लाइन में कर सकता है!


3

अगर हम इसका उपयोग नहीं करना चाहते हैं तो include?यह भी काम करता है:

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

3
कोई भी? भी ब्लॉक स्वीकार करता है: ['बिल्ली', 'कुत्ता', 'घोड़ा']। {। x | x == 'कुत्ता'}
मैकोनस


2

इस तरह से कैसे?

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

यह अभी भी तत्व को खोजने के लिए सरणी पर पुनरावृति करने जा रहा है। फिर उसे उस तत्व का सूचकांक वापस करना होगा।
टिन मैन


2

इसके आसपास दूसरा रास्ता है।

मान लीजिए कि सरणी [ :edit, :update, :create, :show ]अच्छी तरह से है , शायद पूरे सात घातक / बेचैन पाप हैं

और कुछ स्ट्रिंग से एक वैध कार्रवाई खींचने के विचार के साथ आगे का खिलौना :

"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}[,|.| |]/}

1
आपका रेगेक्स, /[,|.| |]#{v.to_s}[,|.| |]/मुझे लगता है कि आप 'एक्शन से घिरे हुए नाम का पता लगाना चाहते थे: अल्पविराम, अवधि, स्थान या कुछ भी नहीं', लेकिन कुछ सूक्ष्म कीड़े हैं। "|update|"वापसी होगी [:update]और "update"वापसी होगी []। वर्ण वर्ग ( [...]) पाइप ( |) का उपयोग वर्णों को अलग करने के लिए नहीं करते हैं । यहां तक ​​कि अगर हम उन्हें समूहों में बदलते हैं ( (...)), तो आप एक खाली चरित्र से मेल नहीं खा सकते हैं। तो शायद आप जो रेगेक्स चाहते हैं/(,|\.| |^)#{v.to_s}(,|\.| |$)/
bkDJ

regex ठीक है (check rubular.com) - और @Ratatino: उदाहरण के लिए अमेज़न इको क्यों होगा?) आप कह सकते हैं: "कृपया मेरी खरीदारी की सूची में चिकन जोड़ें" (और - अच्छी तरह से - फिर आपके पास होगा जोड़ें: सरणी में जोड़ें, लेकिन मुझे लगता है कि आप इसके बारे में प्राप्त करते हैं;)
बट्टा_दिनांक

1
"रेगेक्स ठीक है (rubular.com की जाँच की)"। यह ठीक नहीं है। आपका रेगेक्स एक स्ट्रिंग की शुरुआत या अंत में एक कीवर्ड से मेल नहीं खाएगा (उदाहरण के लिए "मेरे भाई का प्रोफ़ाइल अपडेट करें")। यदि आप शुरुआत या अंत मैच नहीं करना चाहते हैं, तो आपका रेगेक्स अभी भी ठीक नहीं है क्योंकि कीवर्ड के दोनों ओर वर्ण वर्ग होना चाहिए/[,. ]/
bkDJ

जैसा @bkDJ कहता है, regex गलत है। rubular.com/r/4EG04rANz6KET6
टिन मैन

1

यदि आप केवल सही या गलत मूल्य वापस करना चाहते हैं, तो उपयोग करें

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

यदि सूची में मौजूद है तो यह 'डॉग' को लौटा देगा, अन्यथा शून्य।


या उपयोग array.any?{|x| x == 'Dog'}आप अगर है सही / गलत नहीं है (मूल्य) चाहते हैं, लेकिन यह भी इस तरह एक ब्लॉक के खिलाफ तुलना करना चाहते हैं।
Mahemoff

0

यहाँ यह करने का एक और तरीका है:

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

present = arr.size != (arr - [e]).size

1
यह ऐसा करने का एक भयावह अयोग्य तरीका है! मैं नीच नहीं हूं क्योंकि यह तकनीकी रूप से गलत नहीं है, और कोई इसे पढ़ने से रूबी के बारे में कुछ सीख सकता है, लेकिन ऊपर कई बेहतर जवाब हैं।
जिबरिया

कोनहेड, आप सरल कर सकते हैं arr != arr - [e]arr & [e] == [e]उसी तर्ज पर एक और तरीका है।
कैरी स्वेवेलैंड

@CarySwoveland जादूगर की टोपी का मजाक न उड़ाएं ;-)
वैंड मेकर

मैं जादूगर के सिर की बात कर रहा था, न कि टोपी की, सबसे बड़ी इज्जत की।
कैरी स्वेवेलैंड


0

किसी भी सरणी में एक तत्व को खोजने के कई तरीके हैं लेकिन सबसे सरल तरीका है '?' तरीका।

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

2
नोट: जैसा कि इस उत्तर में वर्णित है , विधि in?को ActiveSupportआयात करने की आवश्यकता है require active_support:।
पैट्रिक

यदि आप कोर एक्सटेंशन का उपयोग करते हैं तो इसे सभी ActiveSupport की आवश्यकता नहीं है ।
टिन मैन

0

यदि आप उपयोग नहीं करना चाहते हैं include?तो आप पहले तत्व को एक सरणी में लपेट सकते हैं और फिर जाँच सकते हैं कि लपेटा गया तत्व सरणी के चौराहे और लिपटे तत्व के बराबर है या नहीं। यह समानता के आधार पर एक बूलियन मान लौटाएगा।

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

-1

मुझे हमेशा कुछ करने के विभिन्न तरीकों की सापेक्ष गति को देखने के लिए कुछ बेंचमार्क चलाना दिलचस्प लगता है।

आरंभ, मध्य या अंत में एक सरणी तत्व खोजने से कोई रेखीय खोज प्रभावित होगी लेकिन सेट के विरुद्ध खोज को मुश्किल से प्रभावित करेगी।

एक सेट में एक एरे को परिवर्तित करना प्रसंस्करण समय में एक हिट का कारण बनने वाला है, इसलिए सेट को एक एरे से एक बार बनाएं, या बहुत शुरुआत से सेट के साथ शुरू करें।

यहाँ बेंचमार्क कोड है:

# 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

जब, मेरे मैक ओएस लैपटॉप पर चलाया जाता है, तो इसमें परिणाम होता है:

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

फल और इसकी कार्यप्रणाली के बारे में अधिक जानकारी इसके README में उपलब्ध है ।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.