Licznik, rozmiar, długość… zbyt wiele opcji w Rubim?

140

Nie mogę znaleźć ostatecznej odpowiedzi w tej sprawie i chcę się upewnić, że rozumiem to do „n-tego poziomu” :-)

    a = {"a" => "Witaj", "b" => "Świat"}
    a. liczba # 2
    a. rozmiar # 2
    a. długość # 2

    a = [10, 20]
    a. liczba # 2
    a. rozmiar # 2
    a. długość # 2

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

Zdaję sobie również sprawę, że liczba / rozmiar / długość mają różne znaczenia w przypadku ActiveRecord. W tej chwili interesuje mnie przede wszystkim czysty Ruby (1,92), ale jeśli ktoś chciałby się pochwalić różnicą, jaką robi AR, byłoby to również wdzięczne.

Dzięki!

cbmeeks
źródło
5
Zjawisko, z którym się spotkałeś, jest czasami nazywane TMTOWTDI : Jest więcej niż jeden sposób, aby to zrobić. Ten slogan pochodzi od społeczności Perla, a Perl ma wpływ na Rubiego.
Andrew Grimm,
są to zwykle aliasy dla siebie nawzajem - robią to samo. Jest jedna metoda, o której powinieneś również pamiętać: Array#nitemsktóra zwraca liczbę elementów innych niż NIL w tablicy. Ale to nie jest już dostępne w Ruby 1.9
Tilo

Odpowiedzi:

194

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

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

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

W przypadku, gdy nie podasz parametru do zliczenia, ma on zasadniczo taki sam efekt jak wywołanie length. Jednak może występować różnica w wydajności.

Z kodu źródłowego Array widać , że robią prawie dokładnie to samo. Oto kod C do implementacji array.length:

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

A oto 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.countwykonuje kilka dodatkowych kontroli, ale w końcu nazywa dokładnie ten sam kod: LONG2NUM(RARRAY_LEN(ary)).

Z drugiej strony hashe ( kod źródłowy ) nie wydają się implementować własnej zoptymalizowanej wersji, countwięc używana jest implementacja from Enumerable( kod źródłowy ), która iteruje po wszystkich elementach i zlicza je jeden po drugim.

Ogólnie radziłbym raczej używać length(lub jego aliasu size) niż countwiedzieć, ile elementów jest w sumie.


Odnośnie ActiveRecord, z drugiej strony, nie istotne różnice. sprawdź ten post:

Mark Byers
źródło
10

Istnieje zasadnicza różnica w przypadku aplikacji korzystających z połączeń z bazą danych.

Kiedy używasz wielu ORMów (ActiveRecord, DataMapper itp.), Ogólne zrozumienie jest takie, że .size wygeneruje zapytanie, które zażąda wszystkich pozycji z bazy danych („select * from mytable”), a następnie poda liczbę elementów wynikowe, podczas gdy .count wygeneruje pojedyncze zapytanie ('select count (*) from mytable'), co jest znacznie szybsze.

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

stef
źródło
1
Jest coś do rozważenia counter_cache. Jeśli masz tabelę fooi ma_many bar, będziesz mieć kolumnę w foonamed, bars_countktóra będzie aktualizowana za każdym razem, gdy barzostanie utworzona / zniszczona. Używanie foo.bars.sizejest tym, co sprawdza tę kolumnę (bez odpytywania żadnej bars). foo.bars.countwykonuje rzeczywiste zapytanie, co podważyłoby cel pamięci podręcznej.
Dudo,
7

W większości przypadków (np. Array lub String ) sizejest aliasem dla length.

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

Uwaga: Nie jestem pewien, czy count wymusza ocenę wyliczenia, jeśli blok nie jest określony lub jeśli powoduje zwarcie do, lengthjeśli to możliwe.

Edycja (i dzięki odpowiedzi Marka!): count Bez bloku (przynajmniej dla tablic) nie wymusza oceny. Przypuszczam, że bez formalnego zachowania jest „otwarty” na inne implementacje, jeśli wymuszenie oceny bez predykatu w ogóle ma sens.


źródło
5

Znalazłem dobre oprogramowanie answare pod adresem http://blog.hasmanythrough.com/2008/2/27/count-length-size

W ActiveRecord istnieje kilka sposobów, aby dowiedzieć się, ile rekordów jest w asocjacji i istnieją pewne subtelne różnice w sposobie ich działania.

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

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

post.comments.size - działa 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 nie został jeszcze załadowany, przypomina to wywołanie #count.

Mam też osobiste doświadczenie:

<%= h(params.size.to_s) %> # works_like_that !
<%= h(params.count.to_s) %> # does_not_work_like_that !
profimedica
źródło
2

Istnieje kilka sposobów, aby dowiedzieć się, ile elementów w tablicy, na przykład .length, .counti .size. Jednak lepiej jest używać array.sizezamiast array.count. Ponieważ .sizema lepszą wydajność.

Venkat M
źródło
1

Dodawanie więcej do odpowiedzi Mark Byers. W Rubim metoda array.sizejest aliasem do metody Array # length . Nie ma technicznej różnicy w stosowaniu którejkolwiek z tych dwóch metod. Możliwe, że nie zobaczysz również różnicy w wydajności. Jednak array.countrównież wykonuje to samo zadanie, ale z kilkoma dodatkowymi funkcjami Liczba tablic #

Można go użyć do uzyskania całkowitej liczby elementów w oparciu o pewien warunek. Count można wywołać na trzy sposoby:

Array # count # Zwraca liczbę elementów w tablicy

Array # count n # Zwraca liczbę elementów o wartości n w Array

Tablica # count {| i | i.even?} Zwraca liczbę na podstawie warunku wywołanego dla każdej tablicy elementów

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 wykonują tę samą pracę. Jednak tutaj countrobi się interesująco.

Powiedzmy, że chcę sprawdzić, ile elementów tablicy zawiera tablica o wartości 2

array.count 2    # => 3

Tablica zawiera łącznie trzy elementy o wartości 2.

Teraz chcę znaleźć wszystkie elementy tablicy większe niż 4

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

Tablica ma łącznie 6 elementów, które są> 4.

Mam nadzieję, że daje trochę informacji o countmetodzie.

Prabhakar Undurthi
źródło