Sprawdź, czy tablica nie jest pusta: jakaś?

191

Czy źle jest sprawdzić, czy tablica nie jest pusta za pomocą any?metody?

a = [1,2,3]

a.any?
=> true

a.clear

a.any?
=> false

A może lepiej użyć unless a.empty??

sivabudh
źródło

Odpowiedzi:

248

any?to nie to samo co not empty?w niektórych przypadkach.

>> [nil, 1].any?
=> true
>> [nil, nil].any?
=> false

Z dokumentacji:

Jeśli blok nie zostanie podany, Ruby dodaje domyślny blok {| obj | obj} (czy jest jakiś? zwróci true, jeśli co najmniej jeden z elementów kolekcji nie ma wartości false lub zero).

Marcel Jackwerth
źródło
8
Czy jest jakaś funkcja przeciwna do empty??
RocketR
12
@RocketR możesz chcieć sprawdzić present?metodę.
dantheta
15
@dantastic #present?jest przeznaczony tylko dla Railsów. W czystym Ruby dostaniesz NoMethodError: undefined method 'present?' for Array.
RocketR
6
Nie tylko Rails, Active Support może być używany bez szyn, wystarczy require 'activesupport'.
Sergio A.,
83

Różnica między tablicą oceniającą jej wartości, truea jeśli jest pusta.

Metoda empty?pochodzi z klasy Array
http://ruby-doc.org/core-2.0.0/Array.html#method-i-empty-3F

Służy do sprawdzania, czy tablica zawiera coś, czy nie. Obejmuje to rzeczy, które oceniają false, takie jak nili false.

>> a = []
=> []
>> a.empty?
=> true
>> a = [nil, false]
=> [nil, false]
>> a.empty?
=> false
>> a = [nil]
=> [nil]
>> a.empty?
=> false

Metoda any?pochodzi z modułu Enumerable.
http://ruby-doc.org/core-2.0.0/Enumerable.html#method-i-any-3F

Służy do oceny, czy „dowolna” wartość w tablicy ma wartość true. Podobne metody do tego są none?, all?a one?gdzie oni wszyscy po prostu sprawdzić, ile razy można ocenić prawdziwe. co nie ma nic wspólnego z liczbą wartości znalezionych w tablicy.

przypadek 1

>> a = []
=> []
>> a.any?
=> false
>> a.one?
=> false
>> a.all?
=> true
>> a.none?
=> true

przypadek 2

>> a = [nil, true]
=> [nil, true]
>> a.any?
=> true
>> a.one?
=> true
>> a.all?
=> false
>> a.none?
=> false

przypadek 3

>> a = [true, true]
=> [true, true]
>> a.any?
=> true
>> a.one?
=> false
>> a.all?
=> true
>> a.none?
=> false
Popychacz wielokątów
źródło
31

Prefiks instrukcji wykrzyknikiem informuje, czy tablica nie jest pusta. Więc w twoim przypadku -

a = [1,2,3]
!a.empty?
=> true
Denny Abraham Cheriyan
źródło
27
Podwójna negacja? Mówisz poważnie?
3lvis
29
On nie jest taki poważny!
Alexander Bird
5
Hehe Podwójna negacja nie jest idealna, po prostu wydaje się bardziej czytelna w tym konkretnym przypadku.
Denny Abraham Cheriyan
12
Podwójny negatyw był częścią pierwotnego pytania „Sprawdź, czy tablica nie jest pusta”. To odpowiada na pytanie.
mattfitzgerald
30

Unikaj w any?przypadku dużych tablic.

  • any? jest O(n)
  • empty? jest O(1)

any? nie sprawdza długości, ale faktycznie skanuje całą tablicę w poszukiwaniu prawdziwych elementów.

static VALUE
rb_ary_any_p(VALUE ary)
{
  long i, len = RARRAY_LEN(ary);
  const VALUE *ptr = RARRAY_CONST_PTR(ary);

  if (!len) return Qfalse;
  if (!rb_block_given_p()) {
    for (i = 0; i < len; ++i) if (RTEST(ptr[i])) return Qtrue;
  }
  else {
    for (i = 0; i < RARRAY_LEN(ary); ++i) {
        if (RTEST(rb_yield(RARRAY_AREF(ary, i)))) return Qtrue;
    }
  }
  return Qfalse;
}

empty? z drugiej strony sprawdza tylko długość tablicy.

static VALUE
rb_ary_empty_p(VALUE ary)
{
  if (RARRAY_LEN(ary) == 0)
    return Qtrue;
  return Qfalse;
}

Różnica jest istotna, jeśli masz „rzadkie” tablice, które zaczynają się od wielu nilwartości, takich jak na przykład właśnie utworzona tablica.

akuhn
źródło
W tym przypadku użycia różnica jest istotna tylko wtedy, gdy masz „rzadkie” tablice, które zaczynają się od wielu nilwartości, z „normalnymi” tablicami any?bez bloków zwracających pierwszy element, więc złożoność jest nadal równa O (1), podobnie jak empty?metoda
David Costa
4

Sugeruję używanie unlessi blanksprawdzanie, czy jest puste, czy nie.

Przykład:

unless a.blank?
  a = "Is not empty"
end

Będzie to oznaczać „puste” lub nie. Jeśli „a” jest puste, poniższy kod nie będzie działał.

Dennis
źródło
4
#blank?jest częścią Rails. Jeśli już używają Railsów, #present?to i #blank?tak jest zaprzeczeniem .
Eva,
0

Nie sądzę, żeby korzystanie any?z niego było złe . Często go używam. To jasne i zwięzłe.

Jeśli jednak obawiasz się, że wszystkie nilwartości ją wyrzucają, to naprawdę pytasz, czy tablica ma size > 0. W takim przypadku to martwe proste rozszerzenie (NIE zoptymalizowane, w stylu małpim) zbliży cię.

Object.class_eval do

  def size?
    respond_to?(:size) && size > 0
  end

end

> "foo".size?
 => true
> "".size?
 => false
> " ".size?
 => true
> [].size?
 => false
> [11,22].size?
 => true
> [nil].size?
 => true

Jest to dość opisowe, logicznie pytające „czy ten obiekt ma rozmiar?”. Jest zwięzły i nie wymaga ActiveSupport. I łatwo go zbudować.

Kilka dodatków do przemyślenia:

  1. To nie to samo, co present?z ActiveSupport.
  2. Możesz potrzebować niestandardowej wersji String, która ignoruje białe znaki (podobnie jak present?robi).
  3. Może chcesz nazwę length?dla Stringlub innych rodzajów gdzie może być bardziej opisowe.
  4. Możesz chcieć mieć niestandardowe dla Integeri innych Numerictypów, aby zwracało się logiczne zero false.
lilole
źródło