Ruby: prova l'array


266

Qual è il modo giusto per:

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

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

o per ottenere il conteggio degli elementi in esso?


7
Vuoi un array reale o semplicemente qualcosa di simile a un array?
Kathy Van Stone

1
Non esiste l'indipendenza dai tipi in Ruby. Non preoccuparti che la tua variabile sia un array o meno. Il metodo dovrebbe presupporre che lo sia, e andare avanti e chiamare count su di esso: my_array.count
user132447

Si prega di leggere le risposte di zgchurch e DigitalRoss per Ruby più idiomatici.
DanT

Risposte:


527

Probabilmente vuoi usare kind_of().

>> s = "something"
=> "something"
>> s.kind_of?(Array)
=> false
>> s = ["something", "else"]
=> ["something", "else"]
>> s.kind_of?(Array)
=> true

32
C'è anche is_a?e instance_of?. Vedi stackoverflow.com/questions/3893278/…
Nathan Long

2
Il controllo del tipo è per Java. Vai avanti e chiama semplicemente count sulla variabile. Scrivere unit test per assicurarsi che il metodo funzioni come previsto.
user132447

14
@ user132447 in realtà java è sicuro per i tipi, quindi non devi preoccuparti di controllare alcun tipo
grinch

8
Ho svalutato questo ora poiché non penso che sia una buona pratica in una lingua come Ruby. La risposta di @zgchurch è chiaramente un approccio molto più idiomatico alla domanda. In casi come questo, penso che abbia molto più senso cercare di capire cosa significa l'OP, piuttosto che dargli ciecamente un fucile ...
Per Lundberg

1
Perché dovresti usarla kind_of?()rispetto ad altre soluzioni? Alcune spiegazioni sui vantaggi della tua risposta rispetto ad altre sarebbero utili per i futuri lettori.
AlbertEngelB

151

Sei sicuro che ha bisogno di essere un array? Potresti essere in grado di usare in respond_to?(method)modo che il tuo codice funzioni per cose simili che non sono necessariamente array (forse qualche altra cosa numerabile). Se hai effettivamente bisogno di un array, allora il post che descrive il Array#kind\_of?metodo è il migliore.

['hello'].respond_to?('each')

1
In questo caso sono sicuro che sarà un array. Ma è bello conoscere anche questo metodo. +1
BuddyJoe

Idea interessante, sto usando push / pop su una struttura dati. Qualcosa oltre agli array risponderebbe a quei metodi?
Drew il

3
Se vuoi qualcosa di più simile ad un array, potresti volerlo respond_to?(:to_ary).
Andrew Grimm

22
In generale, questa è una buona pratica per lo sviluppo OO. Ho letto dove qualcuno ha detto fondamentalmente: non immaginare di chiamare metodi sui tuoi oggetti. Stai inviando loro messaggi. Se un oggetto sa come rispondere al tuo messaggio, non ti interessa quale classe sia, o se abbia un metodo chiamato con quello, o se stia creando dinamicamente una risposta tramite method_missing. L'importante è che possa rispondere al tuo messaggio? Ciò consente una migliore astrazione della funzione e dell'implementazione. Puoi modificare l'oggetto che usi in seguito, purché risponda ancora correttamente.
Nathan Long

2
L'unico problema con questo è dire che voglio controllare se qualcosa è un iterabile indicizzato, quindi array, elenchi collegati, ecc.Sarebbero interessanti, ma non voglio archivi di valori chiave come gli hash?
Colton Voege

58

Invece di provare Array,a convertire tutto ciò che ottieni in un livello Array,, il tuo codice deve gestire solo un caso.

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

Ruby ha vari modi per armonizzare un'API che può accettare un oggetto o un Array di oggetti, quindi, ipotizzando perché vuoi sapere se qualcosa è un Array, ho un suggerimento.

L' operatore splat contiene molta magia che puoi cercare, oppure puoi semplicemente chiamare Array(something)che aggiungerà un wrapper Array se necessario. È simile a [*something]in questo caso.

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

Oppure, potresti usare lo splat nella dichiarazione del parametro e poi .flatten, dandoti un diverso tipo di raccoglitore. (Del resto, potresti chiamare anche .flattensopra.)

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]"

E, grazie gregschlom , a volte è più veloce da usare Array(x)perché quando è già un Arraynon ha bisogno di creare un nuovo oggetto.


Quindi stai dicendo che se si tratta di un singolo elemento lo rende un array con un singolo elemento al suo interno?
BuddyJoe

Sì, e se è già un array, lo mantiene senza aggiungere un secondo wrapper di array.
DigitalRoss

2
Non dimenticare: [*nil] => []. Quindi potresti ritrovarti con un array vuoto.
Christopher Oezbek

3
L'utilizzo Array(foo)è molto più efficiente di[*foo]
gregschlom

24

[1,2,3].is_a? Array restituisce true.


1
Cosa aggiunge questo alle risposte che sono state sul sito da quasi sette anni ..?
Martin Tournoij

7
@Carpetsmoker non c'è una risposta concisa che faccia riferimento is_a?a tutto questo thread. Il più vicino è un file [1,2,3].is_a? Enumerable. Penso ancora che valga la pena avere questa risposta.
dipole_moment

5
Sai .. in realtà hai ragione ... Avrei giurato di averlo visto lassù prima: - / Avere un voto positivo!
Martin Tournoij

16

Sembra che tu stia cercando qualcosa che abbia un concetto di oggetti. Quindi consiglierei di vedere se lo è Enumerable. Ciò garantisce anche l'esistenza di #count.

Per esempio,

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

nota che, mentre size, lengthe counttutto funziona per gli array, qui countè il significato giusto - (per esempio, 'abc'.lengthed 'abc'.sizeentrambi funzionano, ma 'abc'.countnon funzionano così).

Attenzione: una stringa is_a? Enumerabile, quindi forse questo non è quello che vuoi ... dipende dal tuo concetto di un oggetto come un array.


11

Provare:

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

EDIT : L'altra risposta è molto meglio della mia.


6

Considera anche l'utilizzo di Array(). Dalla Guida allo stile della community di Ruby :

Usa Array () invece del controllo Array esplicito o [* var], quando hai a che fare con una variabile che vuoi trattare come Array, ma non sei certo che sia un 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) }

Questo produrrà risultati imprevisti quando si passa un hash perché to_aviene chiamato su ogni argomento aggiunto al nuovo array, quindi Array({id: 100})restituisce[[:id, 100]]
brent
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.