ฉันมีค่า'Dog'และอาเร['Cat', 'Dog', 'Bird']ย์
ฉันจะตรวจสอบว่ามีอยู่ในอาร์เรย์โดยไม่วนซ้ำได้อย่างไร มีวิธีง่าย ๆ ในการตรวจสอบว่ามีค่าอยู่หรือไม่
ฉันมีค่า'Dog'และอาเร['Cat', 'Dog', 'Bird']ย์
ฉันจะตรวจสอบว่ามีอยู่ในอาร์เรย์โดยไม่วนซ้ำได้อย่างไร มีวิธีง่าย ๆ ในการตรวจสอบว่ามีค่าอยู่หรือไม่
คำตอบ:
คุณกำลังมองหาinclude?:
>> ['Cat', 'Dog', 'Bird'].include? 'Dog'
=> true%w(Cat Dog Bird).include? 'Dog'
                    #include?ยังคงทำการวนซ้ำ แม้ว่า coder จะถูกบันทึกจากการเขียนลูปอย่างชัดเจน ฉันได้เพิ่มคำตอบที่ทำงานอย่างแท้จริงโดยไม่ต้องวนลูป
                    มีin?วิธีการในActiveSupport(ส่วนหนึ่งของ Rails) ตั้งแต่ v3.1 ตามที่ระบุโดย @campaterson ดังนั้นภายใน Rails หรือถ้าคุณrequire 'active_support'คุณสามารถเขียน:
'Unicorn'.in?(['Cat', 'Dog', 'Bird']) # => falseOTOH ไม่มีinโอเปอเรเตอร์หรือ#in?วิธีการในตัวของ Ruby แม้ว่าจะได้รับการเสนอมาก่อนโดยเฉพาะอย่างยิ่งโดย Yusuke Endohสมาชิกระดับแนวหน้าของ ruby-core
เป็นแหลมออกโดยคนอื่น ๆ วิธีการย้อนกลับ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.5 เท่าArray(ถ้าไม่พบองค์ประกอบ)
บันทึกการปิดท้าย: ระวังเมื่อใช้include?กับ a Range, มีรายละเอียดย่อยดังนั้นให้อ้างอิงเอกสารและเปรียบเทียบกับcover?...
#in?อยู่ในแกน แต่ถ้าคุณใช้ Rails ก็สามารถใช้งานได้ api.rubyonrails.org/classes/Object.html#method-i-in-3F (ฉันรู้ว่านี่คือ Ruby ไม่ใช่คำถาม Rails แต่อาจช่วยให้ทุกคนที่ต้องการใช้งาน#in?ใน Rails ดูเหมือนว่าจะถูกเพิ่มเข้าไปใน Rails 3.1 apidock.com/rails/Object/in%3F
                    ลอง
['Cat', 'Dog', 'Bird'].include?('Dog')ใช้Enumerable#include:
a = %w/Cat Dog Bird/
a.include? 'Dog'หรือถ้าทำการทดสอบเป็นจำนวนมาก1คุณสามารถกำจัดลูป (ที่include?มี) และเปลี่ยนจากO (n)ถึงO (1)ด้วย:
h = Hash[[a, a].transpose]
h['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  ดูEnumerableสำหรับข้อมูลเพิ่มเติม
แรงบันดาลใจของฉันมาจาก " ประเมินว่าอาร์เรย์มีรายการใดในทับทิม "
Ruby มีสิบเอ็ดวิธีในการค้นหาองค์ประกอบในอาร์เรย์
ที่ต้องการหนึ่งinclude?หรือสำหรับการเข้าถึงซ้ำ creat ชุดแล้วโทรหรือ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?เป็นวิธีที่ต้องการ มันใช้forวนลูปภาษา C ภายในที่แบ่งเมื่อองค์ประกอบตรงกับ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) เวลาเข้าถึงโดยที่ไม่ต้องสร้าง Hash ที่เป็นตัวแทนของอาร์เรย์ก่อน หากคุณตรวจสอบสมาชิกภาพซ้ำหลายครั้งในอาร์เรย์เดียวกันการลงทุนครั้งแรกสามารถชำระได้อย่างรวดเร็ว Setไม่ได้ดำเนินการใน C แต่เป็นคลาส Ruby ธรรมดายังคงเวลาเข้าถึง O (1) ของต้นแบบ@hashทำให้คุ้มค่า
นี่คือการใช้งานของ Set class:
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?ที่ใช้กับ O (1) เวลาเข้าถึงในคลาสแฮช
ฉันจะไม่พูดถึงเจ็ดวิธีอื่น ๆ เพราะมันมีประสิทธิภาพน้อยกว่า
จริงๆแล้วมีวิธีการมากขึ้นที่มีความซับซ้อน O (n) เกินกว่า 11 รายการข้างต้น แต่ฉันตัดสินใจที่จะไม่แสดงรายการพวกเขาเนื่องจากพวกเขาสแกนอาร์เรย์ทั้งหมดแทนที่จะทำลายในการแข่งขันครั้งแรก
อย่าใช้สิ่งเหล่านี้:
# bad examples
array.grep(element).any? 
array.select { |each| each == element }.size > 0
...11วิธีที่คุณระบุ ก่อนอื่นคุณแทบจะไม่สามารถนับindexและfind_index(หรือfindและdetect) เป็นวิธีแยกต่างหากเนื่องจากเป็นชื่อที่แตกต่างกันสำหรับวิธีการเดียวกัน ประการที่สองการแสดงออกทั้งหมดที่ลงท้ายด้วย> 0ไม่ถูกต้องซึ่งฉันแน่ใจว่าเป็นการกำกับ (ต่อ)
                    arr.index(e)ยกตัวอย่างเช่นส่งกลับถ้า0 arr[0] == eคุณจะเรียกคืนarr.index(e)ผลตอบแทนnilถ้าeไม่เป็นปัจจุบัน indexไม่สามารถนำมาใช้ แต่หากมีการค้นหาในnil arr(ปัญหาเดียวกันกับrindexที่ไม่ได้อยู่ในรายการ) การแปลงอาเรย์เป็นเซ็ตจากนั้นใช้เมธอด set เป็นบิตของการยืด ทำไมจึงไม่แปลงเป็นแฮช (ด้วยคีย์จากอาร์เรย์และค่าที่กำหนดเอง) จากนั้นใช้เมธอดแฮช แม้ว่าการแปลงไปเป็นชุดเป็น OK มีวิธีการตั้งค่าอื่น ๆ !arr.to_set.add?(e)ที่สามารถนำมาใช้เช่น (ต่อ)
                    arr.count(e) > 0, arr != arr.dup.delete(e) , และarr != arr - [e] arr & [e] == [e]หนึ่งยังสามารถจ้างและselect reject
                    คำตอบหลายข้อเสนอแนะ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 จำนวนมากอยู่ที่นั่น (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 }และตอนนี้เราก็พร้อมที่จะทดสอบการมีอยู่ของคำศัพท์ต่าง ๆ ในอาร์เรย์ของคุณโดยไม่ต้องวนซ้ำในO(log n)เวลานั้นด้วยความเรียบง่ายทางวากยสัมพันธ์เช่นเดียวกับการArray#include?ใช้ซับลิเนียร์Trie#include?:
trie.include? 'bird' #=> true
trie.include? 'duck' #=> falsea.each do ... endอืมม ... ไม่แน่ใจว่ามันไม่ใช่ลูปอย่างไร
                    Set#include?สำหรับผู้ที่กังวลเกี่ยวกับประสิทธิภาพ ควบคู่ไปกับการใช้สัญลักษณ์แทนสตริงมันสามารถเป็นกรณี O (1) โดยเฉลี่ย (ถ้าคุณใช้สตริงจากนั้นเพียงแค่คำนวณแฮชคือ O (n) โดยที่ n คือความยาวของสตริง) หรือถ้าคุณต้องการใช้ห้องสมุดบุคคลที่สามคุณสามารถใช้แฮชที่สมบูรณ์แบบซึ่งเป็นกรณี O ที่เลวร้ายที่สุด
                    Setใช้แฮชเพื่อจัดทำดัชนีสมาชิกดังนั้นจริงๆแล้วSet#include? ควรมีความซับซ้อน O (1) สำหรับการกระจายที่ดีSet(โดยเฉพาะ O (ขนาดอินพุต) สำหรับการแฮชและ O (log (n / bucket-number)) สำหรับ การค้นหา)
                    หากคุณไม่ต้องการวนซ้ำคุณไม่สามารถทำได้ด้วย Arrays คุณควรใช้ชุดแทน
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ข้อเสียคือปุ่มชุดและแฮชสามารถรวมเฉพาะรายการที่ไม่ซ้ำกันและถ้าคุณเพิ่มรายการจำนวนมากทับทิมจะต้องทำสิ่งใหม่ทั้งหมดหลังจากรายการจำนวนหนึ่งเพื่อสร้างแผนที่ใหม่ที่เหมาะกับพื้นที่คีย์ขนาดใหญ่ สำหรับข้อมูลเพิ่มเติมเกี่ยวกับเรื่องนี้ฉันขอแนะนำให้คุณดู " MountainWest RubyConf 2014 - Big O ในแฮ็คโฮมเมดโดย 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)include?หยุดตีแรก?
                    include?หยุดที่การโจมตีครั้งแรก แต่ถ้าการเข้าตีนั้นอยู่ในตอนท้ายของรายการ .... โซลูชันใด ๆ ที่ใช้ Array สำหรับการจัดเก็บจะมีประสิทธิภาพลดลงเมื่อรายการเติบโตโดยเฉพาะอย่างยิ่งเมื่อต้องค้นหาองค์ประกอบที่ส่วนท้ายของ รายการ. Hash and Set ไม่มีปัญหานั้นและจะไม่มีรายการสั่งซื้อและการค้นหาแบบไบนารี
                    นี่เป็นอีกวิธีหนึ่งในการทำสิ่งนี้: ใช้Array#indexวิธีนี้
มันจะส่งกลับดัชนีการเกิดขึ้นครั้งแรกขององค์ประกอบในอาร์เรย์
ตัวอย่างเช่น:
a = ['cat','dog','horse']
if a.index('dog')
    puts "dog exists in the array"
endindex() ยังสามารถนำบล็อก:
ตัวอย่างเช่น:
a = ['cat','dog','horse']
puts a.index {|x| x.match /o/}ส่งคืนดัชนีของคำแรกในอาร์เรย์ที่มีตัวอักษร 'o'
indexยังคงวนซ้ำอาร์เรย์ แต่จะคืนค่าขององค์ประกอบ
                    สนุกกับความเป็นจริง,
คุณสามารถใช้*เพื่อตรวจสอบการเป็นสมาชิกอาร์เรย์ในcaseนิพจน์
case element
when *array 
  ...
else
  ...
endสังเกตุสิ่งเล็ก ๆ น้อย ๆ*ในอนุประโยคเมื่อตรวจสอบนี้เป็นสมาชิกในอาร์เรย์
พฤติกรรมเวทย์มนตร์ปกติของตัวดำเนินการ splat จะมีผลบังคับใช้ตัวอย่างเช่นถ้าarrayไม่ใช่อาร์เรย์จริง ๆ แต่มีองค์ประกอบเดียวที่จะจับคู่กับองค์ประกอบนั้น
whenเป็นไปได้ดังนั้นการตรวจสอบอื่น ๆ ที่เร็วกว่าและกำจัดวัชพืชออกอย่างรวดเร็ว
                    มีหลายวิธีในการทำสิ่งนี้ให้สำเร็จ บางส่วนของพวกเขามีดังนี้:
a = [1,2,3,4,5]
2.in? a  #=> true
8.in? a #=> false
a.member? 1 #=> true
a.member? 8 #=> falseObject#in?เพิ่มเฉพาะ Rails (เช่นActiveSupport) v3.1 + มันไม่สามารถใช้ได้ใน core Ruby
                    หากคุณต้องการตรวจสอบหลายครั้งสำหรับคีย์ใด ๆ แปลง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ประสิทธิภาพของHash # has_key? กับArray # รวมถึง?
พารามิเตอร์แฮช # has_key? อาร์เรย์ # ได้แก่
ความซับซ้อนของเวลาการดำเนินงาน O (1) O (n) 
ประเภทการเข้าถึงการเข้าถึง Hash [แป้น] ถ้ามันซ้ำผ่านแต่ละองค์ประกอบ
                        ส่งคืนค่าใด ๆ จากนั้นอาร์เรย์จนกว่าจะได้รับ
                        true ถูกส่งคืนไปยังการค้นหาค่าใน Array
                        แฮ # has_key? โทร
                        โทร    
สำหรับการตรวจสอบครั้งเดียวใช้งานinclude?ได้ดี
สิ่งนี้จะบอกคุณไม่เพียงว่ามันมีอยู่จริง แต่ยังปรากฏว่ามีกี่ครั้ง:
 a = ['Cat', 'Dog', 'Bird']
 a.count("Dog")
 #=> 1.any?จะกลับมาทันทีที่พบองค์ประกอบแรกที่ตรงกัน.countจะประมวลผลอาร์เรย์ทั้งหมดเสมอ
                    สำหรับสิ่งที่คุ้มค่าเอกสารของ Rubyเป็นแหล่งข้อมูลที่น่าอัศจรรย์สำหรับคำถามประเภทนี้
ฉันจะคำนึงถึงความยาวของอาเรย์ที่คุณกำลังค้นหาด้วย include?วิธีการจะเรียกใช้การค้นหาเชิงเส้นที่มี O (n) ความซับซ้อนซึ่งสามารถได้รับน่าเกลียดสวยขึ้นอยู่กับขนาดของอาร์เรย์
หากคุณกำลังทำงานกับอาร์เรย์ขนาดใหญ่ (เรียงลำดับ) ฉันจะลองเขียนอัลกอริทึมการค้นหาแบบไบนารีซึ่งไม่ควรยากเกินไปและมีกรณีที่แย่ที่สุดของ O (log n)
หรือถ้าคุณกำลังใช้ทับทิม 2.0 bsearchคุณสามารถใช้ประโยชน์จาก
<=>ซึ่งไม่ได้เป็นทุกกรณี ตัวอย่างเช่นสมมติว่าองค์ประกอบของอาร์เรย์มีแฮช
                    คุณสามารถลอง:
ตัวอย่าง: ถ้ามี 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?เหมือนกัน
สามารถทำงานได้ในหนึ่งบรรทัด!
ถ้าเราไม่ต้องการใช้include?สิ่งนี้ก็ใช้งานได้:
['cat','dog','horse'].select{ |x| x == 'dog' }.any?['Cat', 'Dog', 'Bird'].detect { |x| x == 'Dog'}
=> "Dog"
!['Cat', 'Dog', 'Bird'].detect { |x| x == 'Dog'}.nil?
=> true['Cat', nil, 'Dog'].detect { |x| x == nil } #=> nil. ถูกnilพบ?
                    ด้วยวิธีนี้
['Cat', 'Dog', 'Bird'].index('Dog')ถ้าคุณกำลังพยายามที่จะทำเช่นนี้ในMiniTestassert_includesทดสอบหน่วยคุณสามารถใช้ ตัวอย่าง:
pets = ['Cat', 'Dog', 'Bird']
assert_includes(pets, 'Dog')      # -> passes
assert_includes(pets, 'Zebra')    # -> fails มีวิธีอื่น ๆ รอบนี้
สมมติว่าอาร์เรย์เป็น[ :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}[,|.| |]/}/[,|.| |]#{v.to_s}[,|.| |]/ทำให้ฉันคิดว่าคุณต้องการค้นหา 'ชื่อของการกระทำที่ล้อมรอบด้วยหนึ่งใน: จุลภาคระยะเวลาช่องว่างหรืออะไรเลย' แต่มีข้อบกพร่องเล็กน้อย "|update|"จะกลับมา[:update]และจะกลับมา"update" []คลาสอักขระ ( [...]) ไม่ใช้ไพพ์ (| ) เพื่อแยกอักขระ แม้ว่าเราจะเปลี่ยนเป็นกลุ่ม ( (...)) คุณไม่สามารถจับคู่อักขระว่างเปล่าได้ ดังนั้น regex ที่คุณอาจต้องการคือ/(,|\.| |^)#{v.to_s}(,|\.| |$)/
                    /[,. ]/
                    หากคุณต้องการส่งคืนค่าไม่ใช่แค่จริงหรือเท็จใช้
array.find{|x| x == 'Dog'}นี่จะส่งคืน 'สุนัข' หากมีอยู่ในรายการมิฉะนั้นจะไม่มี
array.any?{|x| x == 'Dog'}ถ้าคุณไม่ต้องการ / จริงเท็จ (ไม่ได้ค่า) แต่ยังต้องการที่จะเปรียบเทียบกับบล็อกเช่นนี้
                    นี่เป็นอีกวิธีหนึ่งในการทำสิ่งนี้:
arr = ['Cat', 'Dog', 'Bird']
e = 'Dog'
present = arr.size != (arr - [e]).sizearr != arr - [e]คุณสามารถลดความซับซ้อนของการ arr & [e] == [e]เป็นอีกวิธีในแนวเดียวกัน
                    array = [ 'Cat', 'Dog', 'Bird' ]
array.include?("Dog")มีหลายวิธีในการค้นหาองค์ประกอบในอาร์เรย์ใด ๆ แต่วิธีที่ง่ายที่สุดคือ 'ใน' วิธี.
example:
arr = [1,2,3,4]
number = 1
puts "yes #{number} is present in arr" if number.in? arrหากคุณไม่ต้องการใช้include?คุณสามารถห่อองค์ประกอบในอาร์เรย์ก่อนจากนั้นตรวจสอบว่าองค์ประกอบที่ถูกห่อนั้นเท่ากับจุดตัดของอาร์เรย์และองค์ประกอบที่ห่อหรือไม่ นี่จะคืนค่าบูลีนตามความเสมอภาค
def in_array?(array, item)
    item = [item] unless item.is_a?(Array)
    item == array & item
endฉันมักจะพบว่ามันน่าสนใจที่จะใช้การวัดประสิทธิภาพเพื่อดูความเร็วสัมพัทธ์ของวิธีต่างๆในการทำบางสิ่งบางอย่าง
การค้นหาองค์ประกอบอาเรย์ที่เริ่มต้นกลางหรือท้ายจะส่งผลต่อการค้นหาเชิงเส้นใด ๆ แต่แทบจะไม่ส่งผลกระทบต่อการค้นหากับชุด
การแปลง Array เป็น Set จะทำให้เวลาในการประมวลผลเป็นผลดังนั้นสร้าง Set จาก Array หนึ่งครั้งหรือเริ่มด้วย Set ตั้งแต่เริ่มต้น
นี่คือรหัสมาตรฐาน:
# 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 (หรือแฮช)
อาเรย์ที่เล็กกว่าจะเร็วกว่าวิธีอาเรย์ แต่ก็ยังคงไม่ทันตั้งตัว แต่ในอาเรย์เล็ก ๆ ความแตกต่างอาจจะเล็กน้อย
"ครั้งแรก", "กลาง" และ "สุดท้าย" สะท้อนให้เห็นถึงการใช้first, size / 2และlastสำหรับARRAYสำหรับเป็นองค์ประกอบค้นหา องค์ประกอบนั้นจะถูกใช้เมื่อค้นหาARRAYและSETตัวแปร
มีการเปลี่ยนแปลงเล็กน้อยสำหรับวิธีการที่เปรียบเทียบกับ> 0เพราะการทดสอบควรใช้>= 0สำหรับindexการทดสอบประเภท
ข้อมูลเพิ่มเติมเกี่ยวกับฟรุ๊ตตี้และวิธีการที่สามารถใช้ได้ในของREADME