2010-12-29 8 views
132

io non riesco a trovare una risposta definitiva su questo e voglio fare in modo ho capito questo per il "livello n'th" :-)Conteggio, dimensioni, lunghezza ... troppe scelte in Ruby?

 

    a = { "a" => "Hello", "b" => "World" } 
    a.count # 2 
    a.size # 2 
    a.length # 2 

    a = [ 10, 20 ] 
    a.count # 2 
    a.size # 2 
    a.length # 2 

Quindi, quale da usare? Se voglio sapere se uno ha più di un elemento, allora non sembra avere importanza, ma voglio essere sicuro di capire la vera differenza. Questo vale anche per gli array. Ottengo gli stessi risultati.

Inoltre, mi rendo conto che count/size/length hanno significati diversi con ActiveRecord. Sono interessato principalmente al puro Ruby (1.92) in questo momento, ma se qualcuno vuole prendere in considerazione la differenza, l'AR lo rende anche apprezzato.

Grazie!

+5

Il fenomeno che hai riscontrato viene talvolta chiamato [TMTOWTDI] (http://en.wikipedia.org/wiki/ There theremore_than_one_way_to_do_it): C'è più di un modo per farlo. Questo slogan proviene dalla comunità Perl, e Perl è una delle influenze su Ruby. –

+0

questi sono in genere alias l'uno per l'altro - fanno lo stesso. C'è un metodo da tenere a mente: 'Array # nitems', che restituisce il numero di elementi non NIL in un array. Ma non è più disponibile in Ruby 1.9 – Tilo

risposta

186

Per matrici e hash size è uno pseudonimo per length. Sono sinonimi e fanno esattamente la stessa cosa.

count è più versatile: può richiedere un elemento o un predicato e contare solo gli elementi corrispondenti.

> [1,2,3].count{|x| x > 2 } 
=> 1 

Nel caso in cui si Non fornire un parametro di contare che ha sostanzialmente lo stesso effetto di una chiamata di lunghezza. Tuttavia, ci può essere una differenza di prestazioni.

Possiamo vedere dallo source code for Array che fanno quasi esattamente la stessa cosa. Ecco il codice C per l'attuazione del array.length:

static VALUE 
rb_ary_length(VALUE ary) 
{ 
    long len = RARRAY_LEN(ary); 
    return LONG2NUM(len); 
} 

E qui viene la parte rilevante dall'attuazione di array.count:

static VALUE 
rb_ary_count(int argc, VALUE *argv, VALUE ary) 
{ 
    long n = 0; 

    if (argc == 0) { 
     VALUE *p, *pend; 

     if (!rb_block_given_p()) 
      return LONG2NUM(RARRAY_LEN(ary)); 

     // etc.. 
    } 
} 

Il codice per array.count fa qualche controllo in più, ma alla fine chiama lo stesso identico codice: LONG2NUM(RARRAY_LEN(ary)).

hash (source code) d'altra parte non sembrano per implementare la propria versione ottimizzata del count così l'attuazione da Enumerable (source code) è usato, che itera su tutti gli elementi e conta loro uno per uno.

In generale, consigliamo di utilizzare length (o il suo alias size) anziché count se si desidera sapere quanti elementi ci sono del tutto.


Per quanto riguarda ActiveRecord, d'altra parte, ci sono importanti differenze. controllare questo post:

+9

+1 Yay per andare alla fonte e rispondere alla mia riflessione :-) –

+0

Grazie per una risposta molto informativa! – cbmeeks

7

Nella maggior parte dei casi (ad esempio Array o String) size è un alias per length.

count viene normalmente da Enumerable e può richiedere un blocco di predicato facoltativo. Pertanto enumerable.count {cond} è [approssimativamente] (enumerable.select {cond}).length - può ovviamente bypassare la struttura intermedia in quanto ha solo bisogno del conteggio dei predicati corrispondenti.

Nota: Non sono sicuro se countforze una valutazione dell'enumerazione se il blocco non è specificato o se entra in corto circuito al length se possibile.

Edit (e grazie alla risposta di Marco!):countsenza un blocco (almeno per array) non forza una valutazione. Suppongo che, senza un comportamento formale, sia "aperto" per altre implementazioni, se forzare una valutazione senza un predicato ha mai davvero senso.

10

C'è una differenza cruciale per le applicazioni che fanno uso di connessioni di database.

Quando si utilizzano molti ORM (ActiveRecord, DataMapper, ecc.), La comprensione generale è che .size genererà una query che richiede tutti gli elementi dal database ('select * from mytable') e quindi fornirà il numero di elementi risultanti, mentre .count genererà una singola query ('select count (*) from mytable') che è considerevolmente più veloce.

Poiché questi ORM sono così diffusi, seguo il principio del minimo stupore. In generale, se ho già qualcosa in memoria, allora uso .size, e se il mio codice genererà una richiesta a un database (o un servizio esterno tramite un'API) io uso .count.

+1

Qualcosa da considerare con questo è 'counter_cache'. Se hai una tabella, 'foo', e ha_molto' bar', avrai una colonna in 'pippo' chiamata 'bars_count' che viene aggiornata ogni volta che una' barra' viene creata/distrutta. L'uso di 'foo.bars.size' è ciò che controlla quella colonna (senza effettivamente interrogare alcuna' barra'). 'foo.bars.count' fa la query effettiva, che vanificherebbe lo scopo della cache. – Dudo

5

ho trovato un buon Answare a http://blog.hasmanythrough.com/2008/2/27/count-length-size

In ActiveRecord, ci sono diversi modi per scoprire quanti record sono in un'associazione, e ci sono alcune sottili differenze nel modo in cui funzionano.

post.comments.count - Determina il numero di elementi con una query COUNT SQL . Puoi anche specificare le condizioni per contare solo un sottoinsieme di elementi associati (ad esempio: condizioni => {: nome_origine => "josh"}). Se si imposta una cache contatore sull'associazione, #count restituirà il valore memorizzato nella cache anziché eseguire una nuova query.

post.comments.length - Carica sempre il contenuto dell'associazione in memoria, quindi restituisce il numero di elementi caricati. Si noti che questo non imporrà un aggiornamento se l'associazione era stata precedentemente caricata e quindi i nuovi commenti sono stati creati attraverso un altro modo (ad es. Comment.create (...) invece di post.comments.create (...)).

post.comments.size - Funziona come una combinazione delle due precedenti opzioni . Se la raccolta è già stata caricata, restituirà la sua lunghezza proprio come la chiamata #length. Se non è ancora stato caricato, è come chiamare #count.

anche io ho un'esperienza personale:

<%= h(params.size.to_s) %> # works_like_that ! 
<%= h(params.count.to_s) %> # does_not_work_like_that ! 
1

L'aggiunta di più a Mark Byers risposta. In Ruby il metodo array.size è un alias del metodo Array#length. Non vi è alcuna differenza tecnica nell'utilizzo di uno di questi due metodi. Forse non vedrai alcuna differenza nelle prestazioni. Tuttavia, lo array.count fa lo stesso lavoro ma con alcune funzionalità aggiuntive Array#count

Può essere utilizzato per ottenere il numero totale di elementi in base ad alcune condizioni. Conte può essere chiamato in tre modi:

Array # contano # Restituisce il numero di elementi in Array

Array # contano n # Restituisce il numero di elementi aventi valore n in Array

Array #count {| i | i.even?} Restituisce Cont basano su condizioni invocato su ogni serie di elementi

array = [1,2,3,4,5,6,7,4,3,2,4,5,6,7,1,2,4] 

array.size  # => 17 
array.length # => 17 
array.count # => 17 

Ecco tutti e tre i metodi fanno lo stesso lavoro. Tuttavia qui è dove il count diventa interessante.

Diciamo, voglio trovare il numero di elementi di matrice non l'array contiene con valore

array.count 2 # => 3 

La matrice ha un totale di tre elementi con valore 2.

Ora , voglio trovare tutti gli elementi dell'array maggiore di 4

array.count{|i| i > 4} # =>6 

L'array ha un totale di 6 elementi che sono> di 4.

Spero che fornisca alcune informazioni sul metodo count.

2

Abbiamo diversi modi per scoprire quanti elementi in una matrice come .length, .count e .size. Tuttavia, è preferibile utilizzare array.size anziché array.count. Perché .size è migliore in termini di prestazioni.