gunakan .include? Metode . Ia mengembalikan boolean yang Anda inginkan. Dalam kasus Anda cukup ketik: ['Kucing', 'Anjing', 'Burung'] .sertakan ('Anjing') dan itu harus mengembalikan boolean benar.
Jwan622
jangan gunakan termasuk? metode jika Anda ingin memeriksa beberapa kali untuk nilai yang berbeda untuk hadir dalam array atau tidak karena termasuk? setiap kali akan beralih pada array yang mengambil operasi O (n) untuk mencari setiap kali, Alih-alih membuat hash hash = arr.map {|x| [x,true]}.to_h, sekarang periksa apakah hash.has_key? 'Dog' mengembalikan true atau tidak
aqfaridi
3
Anda tidak dapat benar-benar melakukannya sepenuhnya "tanpa mengulanginya". Secara logis tidak mungkin, komputer tidak dapat mengetahui dengan pasti apakah array berisi elemen tanpa melalui elemen untuk memeriksa apakah ada di antara mereka yang dicari. Kecuali kalau itu kosong, tentu saja. Maka saya kira Anda tidak perlu loop.
Tim M.
Lihat tolok ukur di bawah ini untuk pengujian perbedaan berbagai cara untuk menemukan elemen dalam Array dan Set. stackoverflow.com/a/60404934/128421
Sintaks alternatif:%w(Cat Dog Bird).include? 'Dog'
scarver2
184
Terkadang saya berharap itu "mengandung" tidak termasuk. Saya selalu mencampuradukkannya dengan termasuk.
Henley Chiu
19
Biarkan saya perhatikan bahwa secara internal, #include?masih melakukan perulangan. Coder disimpan dari penulisan loop secara eksplisit. Saya telah menambahkan jawaban yang melakukan tugas dengan benar tanpa perulangan.
Boris Stitnicky
8
@HenleyChiu I yang dipanggil[ 'Dog', 'Bird', 'Cat' ].has? 'Dog'
4
@ AlfonsoVergara Ya, solusi untuk array harus melakukan semacam perulangan secara internal; tidak ada cara untuk menguji keanggotaan array tanpa perulangan. Jika Anda tidak ingin melakukan pengulangan apa pun secara internal, Anda perlu menggunakan struktur data yang berbeda, seperti tabel hash yang sempurna dengan kunci berukuran tetap. Mengingat bahwa tidak ada cara untuk menguji keanggotaan dalam array tanpa mengulang secara internal, saya menafsirkan pertanyaan itu berarti "tanpa harus menulis loop sendiri"
Brian Campbell
250
Ada in?metode di ActiveSupport(bagian dari Rails) sejak v3.1, seperti yang ditunjukkan oleh @campaterson. Jadi di dalam Rails, atau jika Anda require 'active_support', Anda dapat menulis:
'Unicorn'.in?(['Cat','Dog','Bird'])# => false
OTOH, tidak ada inoperator atau #in?metode dalam Ruby itu sendiri, meskipun telah diusulkan sebelumnya, khususnya oleh Yusuke Endoh seorang anggota terkemuka ruby-core.
Seperti yang ditunjukkan oleh orang lain, metode terbalik include?ada, untuk semua Enumerables termasuk Array, Hash, Set, Range:
Perhatikan bahwa jika Anda memiliki banyak nilai dalam array Anda, mereka semua akan diperiksa satu demi satu (yaitu O(n)), sedangkan pencarian untuk hash akan menjadi waktu yang konstan (yaitu O(1)). Jadi, jika array Anda konstan, misalnya, lebih baik menggunakan Set sebagai gantinya. Misalnya:
Sebuah tes cepat menunjukkan bahwa menelepon include?pada elemen 10 Setadalah sekitar 3.5x lebih cepat daripada menelepon pada setara Array(jika unsur ini tidak ditemukan).
Catatan penutup terakhir: berhati-hatilah saat menggunakan include?pada Range, ada kehalusan, jadi rujuk ke dokumen dan bandingkan dengan cover?...
Meskipun Ruby tidak termasuk #in?dalam inti itu, jika Anda menggunakan Rails, itu tersedia. api.rubyonrails.org/classes/Object.html#method-i-in-3F (Saya tahu ini adalah Ruby, bukan pertanyaan Rails, tetapi mungkin membantu siapa pun yang ingin menggunakan #in?Rails. Sepertinya itu ditambahkan di Rails. 3.1 apidock.com/rails/Object/in%3F
ini sintaks yang lebih lama, lihat ^^^ @brian's answer
jahrichie
62
@jahrichie apa sebenarnya yang Anda anggap "sintaksis lama" dalam jawaban ini, tanda kurung opsional?
Dennis
3
saya setuju @ Dennis, ini bukan lebih tua, tanda kurung adalah opsional dan dalam sebagian besar kasus PRAKTEK YANG BAIK .... coba gunakan sertakan tanpa tanda kurung dalam satu baris jika kalimat misalnya, apa yang saya maksudkan adalah bahwa tergantung pada kasus Anda, Anda harus atau harus menggunakan tanda kurung atau tidak (sama sekali tidak terkait dengan sintaks ruby "lama")
d1jhoni1b
Ini adalah satu-satunya sintaks yang bisa saya peroleh dalam operasi ternary.
Michael Cameron
49
Gunakan Enumerable#include:
a =%w/CatDogBird/
a.include?'Dog'
Atau, jika sejumlah tes dilakukan, 1 Anda dapat menyingkirkan loop (yang bahkan include?telah) dan beralih dari O (n) ke O (1) dengan:
h =Hash[[a, a].transpose]
h['Dog']
1. Saya harap ini jelas tetapi untuk mencegah keberatan: ya, hanya untuk beberapa pencarian, Hash [] dan transpose ops mendominasi profil dan masing-masing O (n) sendiri.
Sangat berguna jika Anda ingin memeriksa salah satu / semua string tersebut termasuk dalam string lain / konstan
thanikkal
43
Ruby memiliki sebelas metode untuk menemukan elemen dalam array.
Yang disukai adalah include?atau, untuk akses berulang, membuat Set dan kemudian memanggil include?atau member?.
Inilah semuanya:
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
Mereka semua mengembalikan truenilai ish jika elemen ada.
include?adalah metode yang disukai. Ini menggunakan forloop bahasa-C secara internal yang rusak ketika elemen cocok dengan rb_equal_opt/rb_equalfungsi internal . Itu tidak bisa menjadi jauh lebih efisien kecuali Anda membuat Set untuk cek keanggotaan berulang.
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)){caseQundef:if(rb_equal(e, item))returnQtrue;break;caseQtrue:returnQtrue;}}returnQfalse;}
member?tidak didefinisikan ulang di Arraykelas dan menggunakan implementasi yang tidak dioptimalkan dari Enumerablemodul yang secara harfiah menyebutkan semua elemen:
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();}returnQnil;}
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;}
Diterjemahkan ke kode Ruby hal ini tentang hal berikut:
Keduanya include?dan member?memiliki kompleksitas waktu O (n) karena keduanya mencari array untuk kemunculan pertama dari nilai yang diharapkan.
Kita dapat menggunakan Set untuk mendapatkan O (1) waktu akses dengan biaya harus membuat representasi Hash dari array terlebih dahulu. Jika Anda berulang kali memeriksa keanggotaan pada larik yang sama, investasi awal ini dapat melunasi dengan cepat. Settidak diimplementasikan dalam C tetapi sebagai kelas Ruby biasa, masih waktu akses O (1) yang mendasarinya @hashmembuat ini berharga.
Seperti yang Anda lihat kelas Set hanya membuat @hashinstance internal , memetakan semua objek ke truedan kemudian memeriksa keanggotaan menggunakan Hash#include?yang diimplementasikan dengan O (1) waktu akses di kelas Hash.
Saya tidak akan membahas tujuh metode lainnya karena semuanya kurang efisien.
Sebenarnya ada lebih banyak metode dengan kompleksitas O (n) di luar 11 yang tercantum di atas, tetapi saya memutuskan untuk tidak mencantumkannya karena mereka memindai seluruh array daripada merusak pada pertandingan pertama.
Jangan gunakan ini:
# bad examples
array.grep(element).any?
array.select {|each| each == element }.size >0...
Bagaimana berani mengatakan bahwa Ruby memiliki 11 cara untuk melakukan apa saja! Tidak lebih cepat dari yang Anda katakan bahwa seseorang akan menunjukkan bahwa Anda melewatkan # 12, lalu # 13, dan seterusnya. Untuk menegaskan maksud saya, saya akan menyarankan cara-cara lain, tetapi pertama-tama izinkan saya mempertanyakan 11cara - cara yang telah Anda sebutkan. Pertama, Anda hampir tidak dapat menghitung indexdan find_index(atau finddan detect) sebagai metode yang terpisah, karena mereka hanya nama yang berbeda untuk metode yang sama. Kedua, semua ekspresi yang diakhiri dengan > 0salah, yang saya yakin adalah kekhilafan. (lanjutan)
Cary Swoveland
... arr.index(e), misalnya, mengembalikan 0jika arr[0] == e. Anda akan ingat arr.index(e)pengembalian niljika etidak ada. indextidak dapat digunakan, namun, jika seseorang mencari nildi arr. (Masalah yang sama dengan rindex, yang tidak terdaftar.). Mengubah array menjadi himpunan dan kemudian menggunakan metode himpunan adalah sedikit peregangan. Lalu mengapa tidak dikonversi ke hash (dengan kunci dari array dan nilai arbitrer), lalu gunakan metode hash? Bahkan jika mengonversi ke set tidak apa-apa, ada metode set lain yang bisa digunakan, seperti !arr.to_set.add?(e). (lanjutan)
Cary Swoveland
... Seperti yang dijanjikan, berikut adalah beberapa metode yang lebih yang dapat digunakan: arr.count(e) > 0, arr != arr.dup.delete(e) , arr != arr - [e]dan arr & [e] == [e]. Orang juga bisa menggunakan selectdan reject.
Cary Swoveland
Saya sangat merekomendasikan menggunakan Set jika kriteria adalah tidak ada duplikat diperbolehkan, dan mengetahui apakah ada elemen tertentu dalam daftar. Set adalah SOooo jauh lebih cepat. Array benar-benar tidak boleh digunakan saat pencarian diperlukan; Mereka lebih baik digunakan sebagai antrian di mana barang disimpan sementara untuk diproses secara berurutan. Hash dan Set lebih baik untuk melihat apakah ada sesuatu.
the Tin Man
30
Beberapa jawaban menyarankan Array#include?, tetapi ada satu peringatan penting: Melihat sumbernya, bahkan Array#include?melakukan perulangan:
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)){returnQtrue;}}returnQfalse;}
Cara untuk menguji keberadaan kata tanpa perulangan adalah dengan membuat trie untuk array Anda. Ada banyak implementasi trie di luar sana (google "ruby trie"). Saya akan gunakan rambling-triedalam contoh ini:
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}
Dan sekarang kami siap untuk menguji keberadaan berbagai kata dalam array Anda tanpa mengulanginya, pada O(log n)waktunya, dengan kesederhanaan sintaksis yang sama seperti Array#include?, menggunakan sublinear Trie#include?:
a.each do ... endUmm ... tidak yakin bagaimana itu bukan loop
tckmn
27
Perhatikan bahwa ini sebenarnya termasuk loop; apa pun yang bukan O (1) termasuk semacam loop. Kebetulan itu adalah loop di atas karakter dari string input. Juga perhatikan dari jawaban yang telah disebutkan Set#include?untuk orang-orang yang peduli tentang efisiensi; ditambah dengan menggunakan simbol bukan string, itu bisa menjadi O (1) kasus rata-rata (jika Anda menggunakan string, maka hanya menghitung hash adalah O (n) di mana n adalah panjang string). Atau jika Anda ingin menggunakan perpustakaan pihak ketiga, Anda bisa menggunakan hash sempurna yang merupakan O (1) kasus terburuk.
Brian Campbell
4
AFAIK, Setmenggunakan hash untuk mengindeks anggota-anggotanya, jadi sebenarnya Set#include?harus memiliki kompleksitas O (1) untuk terdistribusi dengan baik Set(lebih khusus O (ukuran input) untuk hashing, dan O (log (n / bucket-number)) untuk pencarian)
Uri Agassi
11
Biaya untuk menciptakan dan memelihara trie sama besarnya. Jika Anda melakukan banyak operasi pencarian pada array, maka memori dan biaya waktu untuk mengisi sebuah trie dan mempertahankannya sepadan, tetapi untuk cek tunggal, atau bahkan ratusan atau ribuan cek, O (n) sangat cocok. Opsi lain yang tidak memerlukan penambahan dependensi adalah mengurutkan array atau mempertahankannya dalam urutan yang terurut, dalam hal ini operasi pencarian biner O (lg n) dapat digunakan untuk memeriksa inklusi.
speakingcode
1
@speaking kode, Anda mungkin benar dari sudut pandang pragmatis. Tetapi OP meminta untuk "memeriksa apakah nilainya ada, tidak lebih, tanpa perulangan". Ketika saya menulis jawaban ini, ada banyak solusi pragmatis di sini, tetapi tidak ada yang benar-benar memenuhi persyaratan literal si penanya. Pengamatan Anda bahwa BST terkait dengan percobaan adalah benar, tetapi untuk string, trie adalah alat yang tepat untuk pekerjaan itu, bahkan Wikipedia tahu banyak . Kompleksitas membangun dan mempertahankan tri yang diimplementasikan dengan baik ternyata sangat menguntungkan.
Boris Stitnicky
18
Jika Anda tidak ingin mengulang, tidak ada cara untuk melakukannya dengan Array. Anda harus menggunakan Set sebagai gantinya.
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
Set berfungsi secara internal seperti Hash, sehingga Ruby tidak perlu mengulang-ulang koleksi untuk menemukan item, karena seperti namanya, ia menghasilkan hash tombol dan membuat peta memori sehingga setiap hash menunjuk ke titik tertentu dalam memori. Contoh sebelumnya dilakukan dengan Hash:
Kelemahannya adalah set dan kunci hash hanya dapat menyertakan item unik dan jika Anda menambahkan banyak item, Ruby harus mengulang semuanya setelah sejumlah item tertentu untuk membangun peta baru yang sesuai dengan ruang tombol yang lebih besar. Untuk lebih lanjut tentang ini, saya sarankan Anda menonton " MountainWest RubyConf 2014 - Big O in a Homemade Hash oleh Nathan Long ".
Jika Anda menggunakan deteksi, maka Anda setidaknya dapat mengurangi perulangan. Deteksi akan berhenti pada item pertama 'terdeteksi' (blok yang dilewati untuk item bernilai true). Selain itu, Anda dapat memberi tahu mendeteksi apa yang harus dilakukan jika tidak ada yang terdeteksi (Anda dapat memasukkan lambda).
aenw
1
@ aenw tidak include?berhenti pada hit pertama?
Kimmo Lehto
Anda memang benar. Saya sangat terbiasa menggunakan mendeteksi bahwa saya lupa tentang memasukkan. terima kasih atas komentar Anda - itu memastikan bahwa saya menyegarkan pengetahuan saya.
aenw
include?berhenti pada hit pertama tetapi jika hit itu di akhir daftar .... Solusi apa pun yang bergantung pada Array untuk penyimpanan akan memiliki kinerja yang menurun ketika daftar tumbuh, terutama ketika harus menemukan elemen di akhir daftar. daftar. Hash dan Set tidak memiliki masalah itu, begitu pula daftar yang dipesan dan pencarian biner.
the Tin Man
Cukup banyak jawaban ini tentang jawaban pertama :)
Kimmo Lehto
17
Ini adalah cara lain untuk melakukan ini: gunakan Array#indexmetode ini.
Ini mengembalikan indeks kemunculan pertama elemen dalam array.
Sebagai contoh:
a =['cat','dog','horse']if a.index('dog')
puts "dog exists in the array"end
index() juga dapat mengambil blok:
Sebagai contoh:
a =['cat','dog','horse']
puts a.index {|x| x.match /o/}
Ini mengembalikan indeks kata pertama dalam array yang berisi huruf 'o'.
indexmasih mengulangi array, itu hanya mengembalikan nilai elemen.
the Tin Man
13
Fakta yang menyenangkan,
Anda dapat menggunakan *untuk memeriksa keanggotaan array dalam caseekspresi.
case element
when*array
...else...end
Perhatikan sedikit *dalam klausa when, ini memeriksa keanggotaan dalam array.
Semua perilaku sulap biasa dari operator percikan berlaku, jadi misalnya jika arraysebenarnya bukan array tetapi satu elemen akan cocok dengan elemen itu.
Ini juga akan menjadi pemeriksaan pertama yang lambat dalam pernyataan kasus, jadi saya akan menggunakannya dalam whenkemungkinan terakhir sehingga yang lain, cek yang lebih cepat, dikeluarkan dengan cepat.
the Tin Man
9
Ada banyak cara untuk mencapai ini. Beberapa di antaranya adalah sebagai berikut:
a =[1,2,3,4,5]2.in? a #=> true8.in? a #=> false
a.member?1#=> true
a.member?8#=> false
Parameter Hash # has_key? Array # termasuk
Kompleksitas Waktu O (1) operasi O (n) operasi
Jenis Akses Mengakses Hash [kunci] jika iterasi melalui setiap elemen
mengembalikan nilai apa pun dari array hingga itu
true dikembalikan ke menemukan nilai dalam Array
Hash # has_key? panggilan
panggilan
Apakah Anda masih belum melalui array untuk mengubahnya menjadi hash?
chrisjacob
2
ya, saya lakukan tetapi sekarang saya memiliki jawaban yang sudah dihitung sebelumnya untuk memeriksa apakah ada elemen dalam array atau tidak. Sekarang, waktu berikutnya ketika saya mencari kata lain, itu akan membutuhkan O (1) untuk kueri, benar meskipun pra-perhitungan akan mengambil O (n). Sebenarnya saya sudah menggunakan include? dalam aplikasi saya di dalam loop untuk memeriksa apakah elemen tertentu ada dalam array atau tidak, itu merusak kinerja, itu diperiksa di ruby-prof, itu adalah hambatan
aqfaridi
1
.... tetapi O (n) ruang dan juga, bukan saatnya O (n), karena seperti yang ditunjukkan oleh @ chris72205, Anda harus beralih melalui array Anda terlebih dahulu. O (1) + O (n) = O (n). Jadi sebenarnya, ini jauh lebih buruk daripada memasukkan?
Rambatino
Bung saya hanya mengatakan jangan gunakan termasuk di dalam lingkaran, untuk memeriksa waktu menggunakan menggunakan baik-baik saja. Jadi tolong baca dulu use case, lebih baik jika Anda perlu memeriksa beberapa kali di dalam loop.
aqfaridi
Mengubah array ke hash adalah mahal, tetapi menggunakan array untuk mencari adalah struktur yang salah. Array lebih baik sebagai antrian di mana pesanan mungkin penting; Hash dan Set lebih baik ketika inklusi / keberadaan / keunikan itu penting. Mulai dengan wadah yang tepat dan masalahnya diperdebatkan.
the Tin Man
4
Ini akan memberi tahu Anda tidak hanya bahwa itu ada tetapi juga berapa kali muncul:
Tidak ada gunanya menggunakan ini kecuali jika Anda ingin tahu berapa kali muncul, karena .any?akan kembali segera setelah menemukan elemen yang cocok pertama, .countakan selalu memproses seluruh array.
Zaz
Meskipun ini secara teknis akan mengetahui apakah ada sesuatu, itu juga BUKAN cara yang tepat untuk melakukannya jika Anda peduli dengan kecepatan.
the Tin Man
4
Untuk apa nilainya, The Ruby docs adalah sumber yang luar biasa untuk pertanyaan-pertanyaan semacam ini.
Saya juga akan mencatat panjang array yang Anda cari. The include?Metode akan menjalankan pencarian linear dengan O (n) kompleksitas yang bisa mendapatkan cukup jelek tergantung pada ukuran array.
Jika Anda bekerja dengan array besar (diurutkan), saya akan mempertimbangkan untuk menulis algoritma pencarian biner yang seharusnya tidak terlalu sulit dan memiliki kasus terburuk O (log n).
Atau jika Anda menggunakan Ruby 2.0, Anda dapat memanfaatkan bsearch.
Pencarian biner mengasumsikan array diurutkan (atau dipesan dalam beberapa bentuk) yang dapat mahal untuk array besar, sering meniadakan keuntungan.
the Tin Man
Pencarian biner juga mengharuskan semua pasangan elemen untuk dapat dibandingkan <=>, yang tidak selalu demikian. Misalkan, misalnya, elemen array adalah hash.
Cary Swoveland
1
@CarySwoveland seharusnya kurang lebih menyiratkan bahwa elemen dalam array yang diurutkan sebanding.
davissp14
4
Anda dapat mencoba:
Contoh: jika Kucing dan Anjing ada dalam array:
(['Cat','Dog','Bird']&['Cat','Dog']).size ==2#or replace 2 with ['Cat','Dog].size
Regex Anda /[,|.| |]#{v.to_s}[,|.| |]/,, membuat saya berpikir Anda ingin menemukan 'nama tindakan yang dikelilingi oleh salah satu dari: koma, titik, ruang, atau tidak sama sekali', tetapi ada beberapa bug halus. "|update|"akan kembali [:update]dan "update"akan kembali []. Kelas karakter ( [...]) tidak menggunakan pipa ( |) untuk memisahkan karakter. Meskipun kami mengubahnya menjadi grup ( (...)), Anda tidak dapat mencocokkan karakter kosong. Jadi regex yang mungkin Anda inginkan adalah/(,|\.| |^)#{v.to_s}(,|\.| |$)/
bkDJ
regexnya ok (centang rubular.com) - dan @Rambatino: kenapa akan seperti Amazon Echo misalnya;) Anda bisa mengatakan: "tolong tambahkan ayam ke daftar belanjaan saya" (dan - yah - maka Anda harus tambahkan: tambahkan ke array, tapi saya rasa Anda mendapatkan intinya;)
walt_die
1
"regex ok (diperiksa rubular.com)". Itu tidak baik. Regex Anda tidak akan cocok dengan kata kunci di awal atau akhir string (mis. "Perbarui profil saudara saya"). Jika Anda tidak ingin mencocokkan awal atau akhir, maka regex Anda masih tidak ok karena kelas karakter di kedua sisi kata kunci seharusnya/[,. ]/
Atau penggunaan array.any?{|x| x == 'Dog'}jika Anda tidak ingin benar / salah (tidak nilai), tetapi juga ingin membandingkan terhadap blok seperti ini.
mahemoff
0
Berikut ini satu cara lagi untuk melakukan ini:
arr =['Cat','Dog','Bird']
e ='Dog'
present = arr.size !=(arr -[e]).size
Ini adalah cara yang sangat tidak efisien untuk melakukan ini! Saya tidak downvoting karena secara teknis tidak salah, dan seseorang mungkin belajar sesuatu tentang Ruby dari membacanya, tetapi ada banyak jawaban yang lebih baik di atas.
jibberia
Conehead, Anda dapat menyederhanakannya arr != arr - [e]. arr & [e] == [e]adalah cara lain di sepanjang garis yang sama.
Catatan: Seperti dijelaskan dalam jawaban ini , metode in?membutuhkan ActiveSupportyang akan diimpor: require active_support.
Patrick
Tidak memerlukan semua ActiveSupport jika Anda menggunakan ekstensi inti .
the Tin Man
0
jika Anda tidak ingin menggunakan, include?Anda pertama-tama dapat membungkus elemen dalam array dan kemudian memeriksa apakah elemen yang dibungkus sama dengan persimpangan array dan elemen yang dibungkus. Ini akan mengembalikan nilai boolean berdasarkan kesetaraan.
Yang mana, ketika dijalankan di laptop Mac OS saya, menghasilkan:
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
Pada dasarnya hasilnya memberitahu saya untuk menggunakan Set untuk semuanya jika saya akan mencari inklusi kecuali saya dapat menjamin bahwa elemen pertama adalah yang saya inginkan, yang sangat tidak mungkin. Ada beberapa overhead ketika memasukkan elemen ke dalam hash, tetapi waktu pencarian jauh lebih cepat, saya tidak berpikir itu harus menjadi pertimbangan. Sekali lagi, jika Anda perlu mencarinya, jangan gunakan Array, gunakan Set. (Atau Hash.)
Semakin kecil Array, semakin cepat metode Array akan berjalan, tetapi mereka masih tidak akan mengikuti, meskipun dalam array kecil perbedaannya mungkin kecil.
"Pertama", "Tengah" dan "Terakhir" mencerminkan penggunaan first, size / 2dan lastuntuk ARRAYuntuk elemen yang dicari. Elemen itu akan digunakan saat mencari ARRAYdan SETvariabel.
Perubahan kecil dibuat untuk metode yang membandingkan > 0karena tes harus >= 0untuk indextes tipe.
Informasi lebih lanjut tentang Fruity dan metodologinya tersedia di README -nya .
hash = arr.map {|x| [x,true]}.to_h
, sekarang periksa apakahhash.has_key? 'Dog'
mengembalikan true atau tidakJawaban:
Anda sedang mencari
include?
:sumber
%w(Cat Dog Bird).include? 'Dog'
#include?
masih melakukan perulangan. Coder disimpan dari penulisan loop secara eksplisit. Saya telah menambahkan jawaban yang melakukan tugas dengan benar tanpa perulangan.[ 'Dog', 'Bird', 'Cat' ].has? 'Dog'
Ada
in?
metode diActiveSupport
(bagian dari Rails) sejak v3.1, seperti yang ditunjukkan oleh @campaterson. Jadi di dalam Rails, atau jika Andarequire 'active_support'
, Anda dapat menulis:OTOH, tidak ada
in
operator atau#in?
metode dalam Ruby itu sendiri, meskipun telah diusulkan sebelumnya, khususnya oleh Yusuke Endoh seorang anggota terkemuka ruby-core.Seperti yang ditunjukkan oleh orang lain, metode terbalik
include?
ada, untuk semuaEnumerable
s termasukArray
,Hash
,Set
,Range
:Perhatikan bahwa jika Anda memiliki banyak nilai dalam array Anda, mereka semua akan diperiksa satu demi satu (yaitu
O(n)
), sedangkan pencarian untuk hash akan menjadi waktu yang konstan (yaituO(1)
). Jadi, jika array Anda konstan, misalnya, lebih baik menggunakan Set sebagai gantinya. Misalnya:Sebuah tes cepat menunjukkan bahwa menelepon
include?
pada elemen 10Set
adalah sekitar 3.5x lebih cepat daripada menelepon pada setaraArray
(jika unsur ini tidak ditemukan).Catatan penutup terakhir: berhati-hatilah saat menggunakan
include?
padaRange
, ada kehalusan, jadi rujuk ke dokumen dan bandingkan dengancover?
...sumber
#in?
dalam inti itu, jika Anda menggunakan Rails, itu tersedia. api.rubyonrails.org/classes/Object.html#method-i-in-3F (Saya tahu ini adalah Ruby, bukan pertanyaan Rails, tetapi mungkin membantu siapa pun yang ingin menggunakan#in?
Rails. Sepertinya itu ditambahkan di Rails. 3.1 apidock.com/rails/Object/in%3FMencoba
sumber
Gunakan
Enumerable#include
:Atau, jika sejumlah tes dilakukan, 1 Anda dapat menyingkirkan loop (yang bahkan
include?
telah) dan beralih dari O (n) ke O (1) dengan:1. Saya harap ini jelas tetapi untuk mencegah keberatan: ya, hanya untuk beberapa pencarian, Hash [] dan transpose ops mendominasi profil dan masing-masing O (n) sendiri.
sumber
Jika Anda ingin memeriksa dengan blok, Anda dapat mencoba
any?
atauall?
.Lihat Enumerable untuk informasi lebih lanjut.
Inspirasi saya berasal dari " mengevaluasi apakah array memiliki item dalam ruby "
sumber
Ruby memiliki sebelas metode untuk menemukan elemen dalam array.
Yang disukai adalah
include?
atau, untuk akses berulang, membuat Set dan kemudian memanggilinclude?
ataumember?
.Inilah semuanya:
Mereka semua mengembalikan
true
nilai ish jika elemen ada.include?
adalah metode yang disukai. Ini menggunakanfor
loop bahasa-C secara internal yang rusak ketika elemen cocok denganrb_equal_opt/rb_equal
fungsi internal . Itu tidak bisa menjadi jauh lebih efisien kecuali Anda membuat Set untuk cek keanggotaan berulang.member?
tidak didefinisikan ulang diArray
kelas dan menggunakan implementasi yang tidak dioptimalkan dariEnumerable
modul yang secara harfiah menyebutkan semua elemen:Diterjemahkan ke kode Ruby hal ini tentang hal berikut:
Keduanya
include?
danmember?
memiliki kompleksitas waktu O (n) karena keduanya mencari array untuk kemunculan pertama dari nilai yang diharapkan.Kita dapat menggunakan Set untuk mendapatkan O (1) waktu akses dengan biaya harus membuat representasi Hash dari array terlebih dahulu. Jika Anda berulang kali memeriksa keanggotaan pada larik yang sama, investasi awal ini dapat melunasi dengan cepat.
Set
tidak diimplementasikan dalam C tetapi sebagai kelas Ruby biasa, masih waktu akses O (1) yang mendasarinya@hash
membuat ini berharga.Berikut ini adalah implementasi dari kelas Set:
Seperti yang Anda lihat kelas Set hanya membuat
@hash
instance internal , memetakan semua objek ketrue
dan kemudian memeriksa keanggotaan menggunakanHash#include?
yang diimplementasikan dengan O (1) waktu akses di kelas Hash.Saya tidak akan membahas tujuh metode lainnya karena semuanya kurang efisien.
Sebenarnya ada lebih banyak metode dengan kompleksitas O (n) di luar 11 yang tercantum di atas, tetapi saya memutuskan untuk tidak mencantumkannya karena mereka memindai seluruh array daripada merusak pada pertandingan pertama.
Jangan gunakan ini:
sumber
11
cara - cara yang telah Anda sebutkan. Pertama, Anda hampir tidak dapat menghitungindex
danfind_index
(ataufind
dandetect
) sebagai metode yang terpisah, karena mereka hanya nama yang berbeda untuk metode yang sama. Kedua, semua ekspresi yang diakhiri dengan> 0
salah, yang saya yakin adalah kekhilafan. (lanjutan)arr.index(e)
, misalnya, mengembalikan0
jikaarr[0] == e
. Anda akan ingatarr.index(e)
pengembaliannil
jikae
tidak ada.index
tidak dapat digunakan, namun, jika seseorang mencarinil
diarr
. (Masalah yang sama denganrindex
, yang tidak terdaftar.). Mengubah array menjadi himpunan dan kemudian menggunakan metode himpunan adalah sedikit peregangan. Lalu mengapa tidak dikonversi ke hash (dengan kunci dari array dan nilai arbitrer), lalu gunakan metode hash? Bahkan jika mengonversi ke set tidak apa-apa, ada metode set lain yang bisa digunakan, seperti!arr.to_set.add?(e)
. (lanjutan)arr.count(e) > 0
,arr != arr.dup.delete(e)
,arr != arr - [e]
danarr & [e] == [e]
. Orang juga bisa menggunakanselect
danreject
.Beberapa jawaban menyarankan
Array#include?
, tetapi ada satu peringatan penting: Melihat sumbernya, bahkanArray#include?
melakukan perulangan:Cara untuk menguji keberadaan kata tanpa perulangan adalah dengan membuat trie untuk array Anda. Ada banyak implementasi trie di luar sana (google "ruby trie"). Saya akan gunakan
rambling-trie
dalam contoh ini:Dan sekarang kami siap untuk menguji keberadaan berbagai kata dalam array Anda tanpa mengulanginya, pada
O(log n)
waktunya, dengan kesederhanaan sintaksis yang sama sepertiArray#include?
, menggunakan sublinearTrie#include?
:sumber
a.each do ... end
Umm ... tidak yakin bagaimana itu bukan loopSet#include?
untuk orang-orang yang peduli tentang efisiensi; ditambah dengan menggunakan simbol bukan string, itu bisa menjadi O (1) kasus rata-rata (jika Anda menggunakan string, maka hanya menghitung hash adalah O (n) di mana n adalah panjang string). Atau jika Anda ingin menggunakan perpustakaan pihak ketiga, Anda bisa menggunakan hash sempurna yang merupakan O (1) kasus terburuk.Set
menggunakan hash untuk mengindeks anggota-anggotanya, jadi sebenarnyaSet#include?
harus memiliki kompleksitas O (1) untuk terdistribusi dengan baikSet
(lebih khusus O (ukuran input) untuk hashing, dan O (log (n / bucket-number)) untuk pencarian)Jika Anda tidak ingin mengulang, tidak ada cara untuk melakukannya dengan Array. Anda harus menggunakan Set sebagai gantinya.
Set berfungsi secara internal seperti Hash, sehingga Ruby tidak perlu mengulang-ulang koleksi untuk menemukan item, karena seperti namanya, ia menghasilkan hash tombol dan membuat peta memori sehingga setiap hash menunjuk ke titik tertentu dalam memori. Contoh sebelumnya dilakukan dengan Hash:
Kelemahannya adalah set dan kunci hash hanya dapat menyertakan item unik dan jika Anda menambahkan banyak item, Ruby harus mengulang semuanya setelah sejumlah item tertentu untuk membangun peta baru yang sesuai dengan ruang tombol yang lebih besar. Untuk lebih lanjut tentang ini, saya sarankan Anda menonton " MountainWest RubyConf 2014 - Big O in a Homemade Hash oleh Nathan Long ".
Inilah patokan:
Dan hasilnya:
sumber
include?
berhenti pada hit pertama?include?
berhenti pada hit pertama tetapi jika hit itu di akhir daftar .... Solusi apa pun yang bergantung pada Array untuk penyimpanan akan memiliki kinerja yang menurun ketika daftar tumbuh, terutama ketika harus menemukan elemen di akhir daftar. daftar. Hash dan Set tidak memiliki masalah itu, begitu pula daftar yang dipesan dan pencarian biner.Ini adalah cara lain untuk melakukan ini: gunakan
Array#index
metode ini.Ini mengembalikan indeks kemunculan pertama elemen dalam array.
Sebagai contoh:
index()
juga dapat mengambil blok:Sebagai contoh:
Ini mengembalikan indeks kata pertama dalam array yang berisi huruf 'o'.
sumber
index
masih mengulangi array, itu hanya mengembalikan nilai elemen.Fakta yang menyenangkan,
Anda dapat menggunakan
*
untuk memeriksa keanggotaan array dalamcase
ekspresi.Perhatikan sedikit
*
dalam klausa when, ini memeriksa keanggotaan dalam array.Semua perilaku sulap biasa dari operator percikan berlaku, jadi misalnya jika
array
sebenarnya bukan array tetapi satu elemen akan cocok dengan elemen itu.sumber
when
kemungkinan terakhir sehingga yang lain, cek yang lebih cepat, dikeluarkan dengan cepat.Ada banyak cara untuk mencapai ini. Beberapa di antaranya adalah sebagai berikut:
sumber
Object#in?
hanya ditambahkan ke Rails (yaituActiveSupport
) v3.1 +. Ini tidak tersedia di Ruby inti.Jika Anda perlu memeriksa beberapa kali untuk kunci apa saja, konversikan
arr
kehash
, dan sekarang periksa di O (1)Kinerja Hash # has_key? versus Array # include?
Untuk sekali pakai cek
include?
baik-baik sajasumber
Ini akan memberi tahu Anda tidak hanya bahwa itu ada tetapi juga berapa kali muncul:
sumber
.any?
akan kembali segera setelah menemukan elemen yang cocok pertama,.count
akan selalu memproses seluruh array.Untuk apa nilainya, The Ruby docs adalah sumber yang luar biasa untuk pertanyaan-pertanyaan semacam ini.
Saya juga akan mencatat panjang array yang Anda cari. The
include?
Metode akan menjalankan pencarian linear dengan O (n) kompleksitas yang bisa mendapatkan cukup jelek tergantung pada ukuran array.Jika Anda bekerja dengan array besar (diurutkan), saya akan mempertimbangkan untuk menulis algoritma pencarian biner yang seharusnya tidak terlalu sulit dan memiliki kasus terburuk O (log n).
Atau jika Anda menggunakan Ruby 2.0, Anda dapat memanfaatkan
bsearch
.sumber
<=>
, yang tidak selalu demikian. Misalkan, misalnya, elemen array adalah hash.Anda dapat mencoba:
Contoh: jika Kucing dan Anjing ada dalam array:
Dari pada:
Catatan:
member?
daninclude?
sama.Ini dapat melakukan pekerjaan dalam satu baris!
sumber
Jika kita ingin tidak menggunakan
include?
ini juga berfungsi:sumber
sumber
['Cat', nil, 'Dog'].detect { |x| x == nil } #=> nil
. Apakahnil
ditemukan?Bagaimana dengan ini?
sumber
Jika Anda mencoba melakukan ini dalam tes unit MiniTest , Anda dapat menggunakannya
assert_includes
. Contoh:sumber
Ada cara lain untuk ini.
Misalkan susunannya adalah
[ :edit, :update, :create, :show ]
, yah mungkin keseluruhan tujuh dosa yang mematikan / tenang .Dan mainan lebih lanjut dengan ide menarik tindakan yang valid dari beberapa string:
Kemudian:
sumber
/[,|.| |]#{v.to_s}[,|.| |]/
,, membuat saya berpikir Anda ingin menemukan 'nama tindakan yang dikelilingi oleh salah satu dari: koma, titik, ruang, atau tidak sama sekali', tetapi ada beberapa bug halus."|update|"
akan kembali[:update]
dan"update"
akan kembali[]
. Kelas karakter ([...]
) tidak menggunakan pipa (|
) untuk memisahkan karakter. Meskipun kami mengubahnya menjadi grup ((...)
), Anda tidak dapat mencocokkan karakter kosong. Jadi regex yang mungkin Anda inginkan adalah/(,|\.| |^)#{v.to_s}(,|\.| |$)/
/[,. ]/
Jika Anda ingin mengembalikan nilai bukan hanya benar atau salah, gunakan
Ini akan mengembalikan 'Anjing' jika ada dalam daftar, jika tidak nihil.
sumber
array.any?{|x| x == 'Dog'}
jika Anda tidak ingin benar / salah (tidak nilai), tetapi juga ingin membandingkan terhadap blok seperti ini.Berikut ini satu cara lagi untuk melakukan ini:
sumber
arr != arr - [e]
.arr & [e] == [e]
adalah cara lain di sepanjang garis yang sama.sumber
sumber
in?
membutuhkanActiveSupport
yang akan diimpor:require active_support
.jika Anda tidak ingin menggunakan,
include?
Anda pertama-tama dapat membungkus elemen dalam array dan kemudian memeriksa apakah elemen yang dibungkus sama dengan persimpangan array dan elemen yang dibungkus. Ini akan mengembalikan nilai boolean berdasarkan kesetaraan.sumber
Saya selalu merasa tertarik untuk menjalankan beberapa tolok ukur untuk melihat kecepatan relatif dari berbagai cara melakukan sesuatu.
Menemukan elemen array di awal, tengah atau akhir akan memengaruhi pencarian linear apa pun, tetapi hampir tidak memengaruhi pencarian terhadap Set.
Mengkonversi Array ke Set akan menyebabkan hit dalam waktu pemrosesan, jadi buat Set dari Array sekali, atau mulai dengan Set dari awal.
Inilah kode patokan:
Yang mana, ketika dijalankan di laptop Mac OS saya, menghasilkan:
Pada dasarnya hasilnya memberitahu saya untuk menggunakan Set untuk semuanya jika saya akan mencari inklusi kecuali saya dapat menjamin bahwa elemen pertama adalah yang saya inginkan, yang sangat tidak mungkin. Ada beberapa overhead ketika memasukkan elemen ke dalam hash, tetapi waktu pencarian jauh lebih cepat, saya tidak berpikir itu harus menjadi pertimbangan. Sekali lagi, jika Anda perlu mencarinya, jangan gunakan Array, gunakan Set. (Atau Hash.)
Semakin kecil Array, semakin cepat metode Array akan berjalan, tetapi mereka masih tidak akan mengikuti, meskipun dalam array kecil perbedaannya mungkin kecil.
"Pertama", "Tengah" dan "Terakhir" mencerminkan penggunaan
first
,size / 2
danlast
untukARRAY
untuk elemen yang dicari. Elemen itu akan digunakan saat mencariARRAY
danSET
variabel.Perubahan kecil dibuat untuk metode yang membandingkan
> 0
karena tes harus>= 0
untukindex
tes tipe.Informasi lebih lanjut tentang Fruity dan metodologinya tersedia di README -nya .
sumber