Проверить массив не пустой: любой?


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} (то есть any? вернет true, если хотя бы один из членов коллекции не равен false или nil).


8
Есть ли какая-либо функция, противоположная empty??
RocketR

12
@RocketR вы можете проверить present?метод.
Дантета

15
@dantastic #present?только для Rails. В чистом рубине вы получите 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?происходит из модуля Enumerable.
http://ruby-doc.org/core-2.0.0/Enumerable.html#method-i-any-3F

Он используется для оценки того, оценивается ли значение «any» в массиве 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
Двойное отрицание? Ты серьезно?
3

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?метод
David Коста

4

Я предлагаю использовать unlessи blankпроверить пусто или нет.

Пример :

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

Это будет знать «пусто» или нет. Если «а» пусто, приведенный ниже код не будет работать.


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.