Apakah ada kebalikan dari memasukkan? untuk Array Ruby?

190

Saya punya logika berikut dalam kode saya:

if !@players.include?(p.name)
  ...
end

@playersadalah sebuah array. Apakah ada metode sehingga saya bisa menghindari itu !?

Idealnya, cuplikan ini adalah:

if @players.does_not_include?(p.name)
  ...
end
Tyler DeWitt
sumber
1
apakah doruby yang valid? saya mendapatkan kesalahan syntax error, unexpected end-of-input(berfungsi jika saya menghapus do)
maxymoo
Lihat stackoverflow.com/a/60404934/128421 untuk benchmark untuk mencari array vs. set.
the Tin Man

Jawaban:

370
if @players.exclude?(p.name)
    ...
end

ActiveSupport menambahkan exclude?metode untuk Array, Hash, dan String. Ini bukan Ruby murni, tetapi digunakan oleh BANYAK pembuat ruby.

Sumber: Ekstensi Inti Dukungan Aktif (Panduan Rails)

dizzy42
sumber
3
Komentar minor: AS menambahkannya ke Enumerable sehingga Anda dapat menggunakannya dengan semua kelas yang menyertakan Enumerable. Bahkan dengan Hash. :)
user2422869
1
Ini harus
ditandai
Metode ini tidak lagi dimuat secara otomatis di Rails 4.2.3 (dan mungkin sebelumnya), Anda harusrequire 'active_support/core_ext/enumerable'
Dennis
96

Ini dia:

unless @players.include?(p.name)
  ...
end

Anda mungkin melihat Panduan Gaya Ruby untuk info lebih lanjut tentang teknik serupa.

Bozhidar Batsov
sumber
Suara positif untuk panduan gaya. Hanya bahan bacaan yang saya butuhkan.
justnorris
1
dapat dibaca untuk satu pernyataan. jika banyak maka lebih baik gunakan negate! atau tambahkan metode Anda sendiri ke kelas array ruby.
Renars Sirotins
3
Lebih suka ini untuk dikecualikan? jawab karena itu murni Ruby.
Dscher
1
Namun tetap aneh ketika bekerja dengan kondisi majemuk. if flag unless @players.include?(p.name)canggung dan if flag && [email protected]?(p.name)menggunakan negasi.
gabe
1
Sementara ifbiarkan hanya truemelewati kondisi, unlessmari lewat falsedan nil. Ini kadang-kadang menyebabkan sulit untuk menemukan bug. Karena itu saya lebih sukaexclude?
ToTenMilan
12

Bagaimana dengan yang berikut:

unless @players.include?(p.name)
  ....
end
ilasno
sumber
Sobat, dengan kecepatan jawaban masuk di situs ini, saya tidak tahu apakah saya akan mendapatkan reputasi tanpa nepotisme yang bagus! :-D Tautan Panduan Gaya adalah sentuhan yang bagus.
ilasno
2
Ini bukan tentang menjadi cepat. Ini tentang menjadi menyeluruh. (Saya telah menemukan) =)
Charles Caldwell
11

Hanya melihat Ruby:

TL; DR

Gunakan none?melewatinya satu blok dengan ==untuk perbandingan:

[1, 2].include?(1)
  #=> true
[1, 2].none? { |n| 1 == n  }
  #=> false

Array#include?menerima satu argumen dan digunakan ==untuk memeriksa setiap elemen dalam array:

player = [1, 2, 3]
player.include?(1)
 #=> true

Enumerable#none?juga dapat menerima satu argumen yang digunakan ===untuk perbandingan. Untuk mendapatkan perilaku yang berlawanan, include?kami menghilangkan parameter dan memberikannya blok ==untuk perbandingan.

player.none? { |n| 7 == n }
 #=> true 
!player.include?(7)    #notice the '!'
 #=> true

Dalam contoh di atas kita dapat menggunakan:

player.none?(7)
 #=> true

Itu karena Integer#==dan Integer#===setara. Tapi pertimbangkan:

player.include?(Integer)
 #=> false
player.none?(Integer)
 #=> false

none?kembali falsekarena Integer === 1 #=> true. Tetapi notinclude?metode yang benar-benar harus dikembalikan true. Seperti yang kami lakukan sebelumnya:

player.none? { |e| Integer == e  }
 #=> true
Sagar Pandya
sumber
7
module Enumerable
  def does_not_include?(item)
    !include?(item)
  end
end

Ok, tapi serius, kecuali berfungsi dengan baik.

Jesse Wolgamott
sumber
1
+1 unlesstidak apa-apa untuk cuplikan cuplikan, tetapi kondisinya mungkin lebih rumit. Saya pikir ini berguna untuk memiliki metode yang dinegasikan ini, mereka memungkinkan lebih banyak kode deklaratif.
tokland
2

Gunakan unless:

unless @players.include?(p.name) do
  ...
end
Mikita Belahlazau
sumber
1

Bisakah Anda menggunakan:

unless @players.include?(p.name) do
...
end

unlesskebalikan dari if, atau Anda dapat menggunakan reject.

Anda dapat rejectelemen yang tidak diperlukan:

@players.reject{|x| x==p.name}

setelah mendapatkan hasil Anda dapat melakukan implementasi Anda.

tekuri
sumber
0

Menggunakan unlessbaik-baik saja untuk pernyataan dengan satu include?klausa tetapi, misalnya, ketika Anda perlu memeriksa dimasukkannya sesuatu dalam satu Arraytetapi tidak dalam yang lain, penggunaan include?dengan exclude?jauh lebih ramah.

if @players.include? && @spectators.exclude? do
  ....
end

Tetapi seperti yang dikatakan dizzy42 di atas, penggunaan exclude?membutuhkan ActiveSupport

MeWillWork4Food
sumber
Itu hanya perlu menggunakan Ekstensi Inti Dukungan Aktif. guide.rubyonrails.org/v3.2/…
the Tin Man
0

Coba sesuatu seperti ini:

@players.include?(p.name) ? false : true
ckshei
sumber
0

Coba ini, ini murni Ruby sehingga tidak perlu menambahkan kerangka periferal

if @players.include?(p.name) == false do 
  ...
end

Saya berjuang dengan logika yang sama selama beberapa hari, dan setelah memeriksa beberapa forum dan papan Q&A sedikit berhasil ternyata solusinya sebenarnya cukup sederhana.

KarmaDeli
sumber
0

Saya mencari ini untuk diri saya sendiri, menemukan ini, dan kemudian solusi. Orang menggunakan metode yang membingungkan dan beberapa metode yang tidak berfungsi dalam situasi tertentu atau tidak sama sekali.

Saya tahu ini sudah terlambat sekarang, mengingat ini telah diposting 6 tahun yang lalu, tapi semoga pengunjung yang akan datang menemukan ini (dan mudah-mudahan, ini dapat membersihkan kode mereka, dan Anda.)

Solusi sederhana:

if not @players.include?(p.name) do
  ....
end
Voidableryzer
sumber