2010-12-29 12 views
132

I nie wydaje się znaleźć ostateczną odpowiedź na ten temat i chcę się upewnić, rozumiem to „poziomu n'th” :-)Liczba, rozmiar, długość ... zbyt wiele wyborów w 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 

Więc który w użyciu? Jeśli chcę wiedzieć, czy ma więcej niż jeden element, to nie ma to znaczenia, ale chcę się upewnić, że rozumiem prawdziwą różnicę. Dotyczy to również tablic. Otrzymuję takie same wyniki.

Ponadto zdaję sobie sprawę, że liczba/rozmiar/długość mają różne znaczenia w ActiveRecord. W tej chwili interesuję się czystym Rubinem (1.92), ale jeśli ktokolwiek chce głosować na różnicę AR, to też będzie to docenione.

Dzięki!

+5

Zjawisko, które napotkano, jest czasami nazywane [TMTOWTDI] (http://en.wikipedia.org/wiki/There's_more_than_one_way_to_do_it): Jest więcej niż jeden sposób, aby to zrobić. To hasło pochodzi od społeczności Perla, a Perl jest jednym z wpływów na Ruby. –

+0

są to zwykle aliasy dla siebie - robią to samo. Jest jedna metoda, o której powinieneś pamiętać: 'Array # nitems', która zwraca liczbę elementów innych niż NIL w tablicy. Ale to nie jest już dostępne w Ruby 1.9. – Tilo

Odpowiedz

186

Dla tablic i skrótów size to alias dla length. Są synonimami i robią dokładnie to samo.

count jest bardziej wszechstronny - może przyjąć element lub predykat i policzyć tylko te elementy, które pasują do siebie.

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

W przypadku ty nie zapewnić parametr liczyć ma w zasadzie taki sam efekt jak długość dzwoni. Może jednak występować różnica w wydajności.

Widzimy od source code for Array, że robią prawie dokładnie to samo. Oto kod C do wdrożenia array.length:

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

I tu jest odpowiednia część z realizacji 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.. 
    } 
} 

Kod dla array.count robi kilka dodatkowych kontroli, ale w końcu wywołuje ten sam kod: LONG2NUM(RARRAY_LEN(ary)).

Hashe (source code) z drugiej strony nie wydaje się, aby realizować swoje własne zoptymalizowaną wersję count więc służy realizacja od Enumerable (source code), który wykonuje iteracje nad wszystkimi elementami i liczy je jeden po drugim.

Ogólnie zalecam używanie length (lub jego aliasy size) zamiast count, jeśli chcesz wiedzieć, ile elementów jest w ogóle.


chodzi ActiveRecord, z drugiej strony, tam istotne różnice. sprawdzić to wpis:

+9

+1 Yay za przejście do źródła i odpowiadanie na moje rozmyślania :-) –

+0

Dzięki za bardzo pouczającą odpowiedź! – cbmeeks

7

W większości przypadków (np Array lub String) size stanowi ps do length.

count zwykle pochodzi z Enumerable i może przyjmować opcjonalny blok predykatów. Tak więc enumerable.count {cond} jest [w przybliżeniu] (enumerable.select {cond}).length - może oczywiście ominąć strukturę pośrednią, ponieważ potrzebuje tylko liczby zgodnych predykatów.

Uwaga: Nie jestem pewien, czy countsiły ocenę wyliczenie jeżeli blok nie jest określony, czy też zwarcie do length jeśli to możliwe.

Edit (i dzięki odpowiedź Marka!):countbez bloku (przynajmniej dla tablic) nie siły oceny. Przypuszczam, że bez formalnego zachowania jest "otwarty" dla innych implementacji, jeśli wymuszenie oceny bez predykatu nawet tak naprawdę ma sens.

10

Istnieje zasadnicza różnica dla aplikacji korzystających z połączeń z bazami danych.

W przypadku korzystania z wielu ORMów (ActiveRecord, DataMapper itp.) Ogólne zrozumienie polega na tym, że .size wygeneruje zapytanie, które zażąda wszystkich pozycji z bazy danych ("wybierz * z mytable"), a następnie poda liczba elementów wynikowych, podczas gdy .count wygeneruje pojedyncze zapytanie ("wybierz liczbę (*) z mytable"), które jest znacznie szybsze.

Ponieważ te ORM są tak rozpowszechnione, kieruję się zasadą najmniejszego zdziwienia. Generalnie, jeśli mam już coś w pamięci, używam .size, a jeśli mój kod wygeneruje żądanie do bazy danych (lub usługi zewnętrznej za pośrednictwem API), używam .count.

+1

Coś, co należy wziąć pod uwagę, to 'counter_cache'. Jeśli masz tabelę, 'foo', i ma ona' wiele 'paska', będziesz miał kolumnę w 'foo' o nazwie' bars_count', która będzie aktualizowana za każdym razem, gdy 'bar' zostanie utworzony/zniszczony. Używanie 'foo.bars.size' jest tym, co sprawdza tę kolumnę (bez faktycznego sprawdzania jakichkolwiek' słupków'). 'foo.bars.count' ma aktualne zapytanie, które pokonałoby cel pamięci podręcznej. – Dudo

5

znalazłem dobrą answare na http://blog.hasmanythrough.com/2008/2/27/count-length-size

W ActiveRecord, istnieje kilka sposobów, aby dowiedzieć się, ile rekordów są w związku, a istnieją pewne subtelne różnice w sposobie one działają.

post.comments.count - Określ liczbę elementów za pomocą zapytania SQL COUNT. Można również określić warunki, aby zliczyć tylko podzbiór powiązanych elementów (np .: warunki =>: author_name => "josh"}). Jeśli skonfigurujesz licznik pamięci podręcznej w powiązaniu, #count zwróci tę buforowaną wartość zamiast wykonywania nowego zapytania.

post.comments.length - To zawsze ładuje zawartość skojarzenia do pamięci, a następnie zwraca liczbę załadowanych elementów. Pamiętaj, że to nie wymusi aktualizacji, jeśli powiązanie zostało wcześniej załadowane , a następnie nowe komentarze zostały utworzone przez inny sposób (np. Comment.create (...) zamiast post.comments.create (...)).

post.comments.size - działa to jako połączenie dwóch poprzednich opcji . Jeśli kolekcja została już załadowana, zwróci swoją długość , podobnie jak wywołanie # length. Jeśli jeszcze nie został załadowany, jest to , takie jak wywołanie # count.

Również Mam osobiste doświadczenie:

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

Dodajesz więcej Mark Byers odpowiedź. W języku Ruby metoda array.size jest aliasem dla metody Array#length. Nie ma żadnej technicznej różnicy w używaniu żadnej z tych dwóch metod. Prawdopodobnie nie zauważysz żadnej różnicy w wydajności. Jednak model array.count wykonuje tę samą pracę, ale z pewnymi dodatkowymi funkcjami. Może być używany do uzyskania całkowitej liczby elementów na podstawie pewnych warunków. Ilość można nazwać na trzy sposoby:

Array # liczyć # Zwraca liczbę elementów w tablicy

Array # liczyć n # Zwraca liczbę elementów mających wartość N w tablicy

Array #count {| i | i.even?} Zwraca Liczba oparciu o stan wywołany na każdym elemencie tablicy

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 

Tutaj wszystkie trzy metody wykonywania tej samej pracy. Jednak tutaj jest count staje się interesująca.

Załóżmy, chcę dowiedzieć ile tablica elementów ma tablica zawiera o wartości

array.count 2 # => 3 

Tablica posiada w sumie trzy elementy o wartości jako 2.

Teraz Chcę znaleźć wszystkie elementy tablicy większa niż 4

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

tablica ma całkowitą 6 elementów, które są> niż 4.

Mam nadzieję, że daje pewne informacje na temat metody count.

2

Mamy kilka sposobów, aby dowiedzieć się, ile elementów w tablicy, takich jak .length, .count i .size. Jednak lepiej jest użyć array.size niż array.count. Ponieważ .size zapewnia lepszą wydajność.

Powiązane problemy