Ruby - test untuk array

265

Apa cara yang tepat untuk:

is_array("something") # => false         (or 1)

is_array(["something", "else"]) # => true  (or > 1)

atau untuk mendapatkan jumlah item di dalamnya?

BuddyJoe
sumber
7
Apakah Anda ingin array yang sebenarnya, atau hanya sesuatu yang mirip array?
Kathy Van Stone
1
Tidak ada keamanan jenis di Ruby. Jangan khawatir tentang variabel Anda menjadi array atau tidak. Metode ini harus mengasumsikan bahwa itu adalah, dan teruskan dan panggil hitung di atasnya: my_array.count
user132447
Silakan baca jawaban oleh zgchurch dan DigitalRoss untuk mengetahui Ruby yang lebih idiomatis.
DanT

Jawaban:

516

Anda mungkin ingin menggunakannya kind_of().

>> s = "something"
=> "something"
>> s.kind_of?(Array)
=> false
>> s = ["something", "else"]
=> ["something", "else"]
>> s.kind_of?(Array)
=> true
ry.
sumber
31
Ada juga is_a?dan instance_of?. Lihat stackoverflow.com/questions/3893278/…
Nathan Long
2
Pengecekan tipe untuk Java. Silakan dan panggil saja jumlah variabel. Tulis pengujian unit untuk memastikan metode ini berfungsi seperti yang diharapkan.
user132447
14
@ user132447 sebenarnya java adalah tipe aman sehingga Anda tidak perlu khawatir tentang memeriksa semua jenis
grinch
8
Saya menurunkan ini sekarang karena saya pikir ini bukan praktik yang baik dalam bahasa seperti Ruby. Jawaban oleh @zgchurch jelas merupakan pendekatan yang jauh lebih idiomatis terhadap pertanyaan itu. Dalam kasus-kasus seperti ini, saya pikir jauh lebih masuk akal untuk mencoba dan mencari tahu apa arti OP, daripada secara membabi buta memberinya senapan ...
Per Lundberg
1
Mengapa Anda ingin menggunakan kind_of?()solusi lain? Beberapa penjelasan tentang manfaat jawaban Anda terhadap orang lain akan membantu pembaca di masa mendatang.
AlbertEngelB
148

Apakah Anda yakin itu perlu array? Anda mungkin dapat menggunakan respond_to?(method)sehingga kode Anda akan bekerja untuk hal-hal serupa yang belum tentu array (mungkin beberapa hal yang dapat diatasi). Jika Anda benar-benar membutuhkan array, maka postingan yang menjelaskan Array#kind\_of?metode yang terbaik.

['hello'].respond_to?('each')
zgchurch
sumber
1
Dalam hal ini saya yakin itu akan menjadi Array. Tapi senang mengetahui metode ini juga. +1
BuddyJoe
Ide menarik, saya menggunakan push / pop pada struktur data. Apakah selain array akan merespon metode tersebut?
Drew
3
Jika Anda menginginkan sesuatu yang lebih mirip array, Anda mungkin menginginkannya respond_to?(:to_ary).
Andrew Grimm
21
Secara umum, ini adalah praktik yang baik untuk pengembangan OO. Saya membaca di mana seseorang pada dasarnya berkata: jangan membayangkan bahwa Anda memanggil metode pada objek Anda. Anda mengirimi mereka pesan. Jika suatu objek tahu bagaimana menanggapi pesan Anda, Anda tidak peduli kelas apa itu, atau apakah ada metode yang menamainya, atau apakah secara dinamis membuat respons melalui metode_missing. Yang penting adalah, bisakah itu menanggapi pesan Anda? Ini memungkinkan abstraksi fungsi dan implementasi yang lebih baik. Anda dapat mengubah objek apa yang Anda gunakan nanti, selama masih merespons dengan benar.
Nathan Long
2
Satu-satunya masalah dengan ini adalah mengatakan saya ingin memeriksa apakah ada sesuatu yang dapat diindeks, jadi array, daftar tertaut, dll. Akan keren, tapi saya tidak ingin menyimpan nilai kunci seperti hash?
Colton Voege
58

Alih-alih menguji Array,hanya mengkonversi apa pun yang Anda dapatkan menjadi satu tingkat Array,sehingga kode Anda hanya perlu menangani satu kasus.

t = [*something]     # or...
t = Array(something) # or...
def f *x
    ...
end

Ruby memiliki berbagai cara untuk menyelaraskan API yang dapat mengambil objek atau Array objek, jadi, tebak mengapa Anda ingin tahu apakah ada sesuatu yang terjadi. Array, saya punya saran.

The percikan Operator berisi banyak sihir Anda dapat melihat, atau Anda hanya dapat memanggil Array(something)yang akan menambahkan wrapper Array jika diperlukan. Mirip dengan [*something]kasus yang satu ini.

def f x
  p Array(x).inspect
  p [*x].inspect
end
f 1         # => "[1]"
f [1]       # => "[1]"
f [1,2]     # => "[1, 2]"

Atau, Anda bisa menggunakan percikan dalam deklarasi parameter dan kemudian .flatten, memberi Anda jenis kolektor yang berbeda. (Dalam hal ini, Anda bisa menelepon ke .flattenatas juga.)

def f *x
  p x.flatten.inspect
end         # => nil
f 1         # => "[1]"
f 1,2       # => "[1, 2]"
f [1]       # => "[1]"
f [1,2]     # => "[1, 2]"
f [1,2],3,4 # => "[1, 2, 3, 4]"

Dan, terima kasih gregschlom , kadang-kadang lebih cepat hanya digunakan Array(x)karena ketika sudah menjadi Arraytidak perlu membuat objek baru.

DigitalRoss
sumber
Jadi Anda mengatakan jika itu adalah item tunggal, itu membuatnya menjadi array dengan item tunggal di dalamnya?
BuddyJoe
Ya, dan jika sudah merupakan array, ia menyimpannya tanpa menambahkan pembungkus array kedua.
DigitalRoss
2
Jangan lupa: [*nil] => []. Jadi, Anda mungkin berakhir dengan array kosong.
Christopher Oezbek
3
Menggunakan Array(foo)jauh lebih efisien daripada[*foo]
gregschlom
23

[1,2,3].is_a? Array mengevaluasi ke true.

momen dipol
sumber
1
Apa yang ini tambahkan ke jawaban yang telah ada di situs selama hampir tujuh tahun ..?
Martin Tournoij
6
@Carpetsmoker tidak ada jawaban ringkas yang merujuk is_a?pada keseluruhan utas ini. Yang terdekat adalah a [1,2,3].is_a? Enumerable. Saya masih berpikir ada baiknya sementara memiliki jawaban ini.
dipole_moment
4
Anda tahu .. Anda sebenarnya benar ... Saya berani bersumpah saya melihat itu di sana sebelumnya: - / Selamat!
Martin Tournoij
16

Sepertinya Anda mencari sesuatu yang memiliki beberapa konsep barang. Dengan demikian saya akan merekomendasikan melihat apakah itu Enumerable. Itu juga menjamin keberadaan #count.

Sebagai contoh,

[1,2,3].is_a? Enumerable
[1,2,3].count

perhatikan bahwa, sementara size, lengthdan countsemua berfungsi untuk array, countadalah makna yang tepat di sini - (misalnya, 'abc'.lengthdan 'abc'.sizekeduanya berfungsi, tetapi 'abc'.counttidak berfungsi seperti itu).

Perhatian: string is_a? Dapat dihitung, jadi mungkin ini bukan yang Anda inginkan ... tergantung pada konsep Anda tentang objek seperti array.

Peter
sumber
11

Mencoba:

def is_array(a)
    a.class == Array
end

EDIT : Jawaban lainnya jauh lebih baik dari pada saya.

Lucas Jones
sumber
6

Juga pertimbangkan untuk menggunakan Array(). Dari Panduan Gaya Komunitas Ruby :

Gunakan Array () alih-alih centang Array eksplisit atau [* var], saat berurusan dengan variabel yang ingin Anda perlakukan sebagai Array, tetapi Anda tidak yakin itu adalah array.

# bad
paths = [paths] unless paths.is_a? Array
paths.each { |path| do_something(path) }

# bad (always creates a new Array instance)
[*paths].each { |path| do_something(path) }

# good (and a bit more readable)
Array(paths).each { |path| do_something(path) }
GuyPaddock
sumber
Ini akan menghasilkan hasil yang tidak terduga ketika melewati Hash karena to_adipanggil pada setiap argumen yang ditambahkan ke array baru, jadi Array({id: 100})kembali[[:id, 100]]
brent