Перевірте, чи масив не порожній: будь-який?


191

Чи погано перевірити, чи масив не порожній за допомогою any?методу?

a = [1,2,3]

a.any?
=> true

a.clear

a.any?
=> false

Або краще використовувати unless a.empty??

Відповіді:


248

any?не те саме, що not empty?в деяких випадках.

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

З документації:

Якщо блок не заданий, Ruby додає неявний блок {| obj | obj} (це будь-яке? повернеться істинним, якщо принаймні один із членів колекції не відповідає дійсності).


8
Чи є якась функція, протилежна empty??
RocketR

12
@RocketR Ви можете скористатися present?методом оформлення замовлення .
дантета

15
@dantastic #present?- це лише Рейки. У чистому Ruby ви отримаєте NoMethodError: undefined method 'present?' for Array.
RocketR

6
Не зовсім Rails, Active Support можна використовувати без перил, просто потрібно require 'activesupport'.
Серхіо А.

83

Різниця між масивом, що оцінює його значення, trueабо якщо він порожній.

Метод empty?походить з класу Array
http://ruby-doc.org/core-2.0.0/Array.html#method-i-empty-3F

Він використовується для перевірки, чи містить масив щось чи ні. Сюди входять речі, які оцінюються false, такі як nilі false.

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

Метод any?походить від модуля «Численні».
http://ruby-doc.org/core-2.0.0/Enumerable.html#method-i-any-3F

Він використовується для оцінки, чи "будь-яке" значення в масиві оцінюється на true. Подібні методи єnone? , all?і one?там, де всі вони просто перевіряють, щоб побачити, скільки разів можна оцінити істинність. що не має нічого спільного з підрахунком значень, знайдених у масиві.

випадок 1

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

випадок 2

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

випадок 3

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

31

Префіксація висловлювання знаком оклику дасть вам знати, чи масив не порожній. Тож у вашому випадку -

a = [1,2,3]
!a.empty?
=> true

27
Подвійне заперечення? Ти серйозно?
3lvis

29
Він такий несерйозний!
Олександр Птах

5
Хе-хе. Подвійне заперечення не є ідеальним, просто здається більш читабельним у цьому конкретному випадку.
Денні Авраам Черіан

12
Подвійний мінус був частиною оригінального питання "Перевірити наявність масиву не порожнім". Це відповідає на питання.
mattfitzgerald

30

Уникайте any?великих масивів.

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

any? не перевіряє довжину, але насправді сканує весь масив на предмет правдивих елементів.

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? з іншого боку перевіряє лише довжину масиву.

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

Різниця актуальна, якщо у вас є "розріджені" масиви, які починаються з великої кількості nilзначень, як, наприклад, щойно створений масив.


У цьому випадку використання різниця є актуальною лише у тому випадку, якщо у вас є "розріджені" масиви, які починаються з великої кількості nilзначень, при "нормальних" масивах any?без блоку повертається на першому елементі, тому складність все ще O (1), як empty?метод
Девід Коста

4

Я запропоную використовувати unlessта blankперевірити, чи це порожньо чи ні.

Приклад:

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

Це знатиме "а" порожнє чи ні. Якщо "a" порожній, наведений нижче код не запускається.


4
#blank?є частиною Rails. Якщо вони вже використовують Rails, #present?це #blank?все одно заперечення .
Єва

0

Я не думаю, що це взагалі погано використовувати any?. Я цим багато користуюся. Це чітко і стисло.

Однак якщо ви стурбовані тим, що всі nilзначення скидаються, то ви справді запитуєте, чи є масив size > 0. У такому випадку це мертве просте розширення (НЕ оптимізоване в мавповому стилі) наблизить вас.

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

Це досить описово, логічно запитуючи "чи має цей об’єкт розмір?". І це лаконічно, і для нього не потрібен ActiveSupport. І це легко будувати.

Деякі додаткові речі, про які варто подумати:

  1. Це не те саме, що в present?ActiveSupport.
  2. Ви можете скористатись власною версією String, яка ігнорує пробіли (як present?і).
  3. Можливо, ви хочете, щоб ім'я length?для Stringінших або інших типів, де воно може бути більш описовим.
  4. Можливо, ви хочете, щоб це було призначено для Integerінших та інших Numericтипів, щоб повертався логічний нуль false.
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.