Книга: Программирование на языке Ruby

8.1.6. Выборка из массива по заданному критерию

8.1.6. Выборка из массива по заданному критерию

Иногда нужно найти в массиве один или несколько элементов так, как будто мы опрашиваем таблицу в базе данных. Для этого есть несколько способов; рассмотренные ниже реализованы в подмешанном модуле Enumerable.

Метод detect находит не больше одного элемента. Он принимает блок (которому элементы передаются последовательно) и возвращает первый элемент, для которого значение блока оказывается равным true.

x = [5, 8, 12, 9, 4, 30]
# Найти первый элемент, кратный 6.
x.detect {|e| e % 6 == 0 } #12
# Найти первый элемент, кратный 7.
c.detect {|e| e % 7 == 0 } # nil

Разумеется, хранящиеся в массиве объекты могут быть произвольно сложными, равно как и условие, проверяемое в блоке.

Метод find — синоним detect. Метод find_all возвращает несколько элементов, а не один-единственный; select — синоним find_all.

# Продолжение предыдущего примера...
x.find {|e| e % 2 == 0}     # 8
x.find_all {|e| e % 2 == 0} # [8, 12, 4, 30]
x.select {|e| e % 2 == 0}   # [8, 12, 4, 30]

Метод grep вызывает оператор сравнения (то есть оператор ветвящегося равенства) для сопоставления каждого элемента с заданным образцом. В простейшей форме он возвращает массив, состоящий из элементов, соответствующих образцу. Так как используется оператор ===, то образец не обязан быть регулярным выражением. (Имя grep пришло из UNIX и связано с командой старого редактора g/re/p.)

а = %w[January February March April May]
a.grep(/ary/}  # ["January, "February"]
b = [1, 20, 5, 7, 13, 33, 15, 28]
b.grep(12..24) # [20, 13, 15]

Существует также блочная форма, которая позволяет преобразовать каждый результат перед записью в массив. Получающийся в результате массив содержит значения, возвращенные блоком, а не те, что были в блок первоначально переданы:

# продолжение предыдущего примера...
# Будем сохранять длины строк.
a.grep(/ary/) {|m| m.length} # [7, 8]
# Будем сохранять квадраты исходных элементов.
b.grep(12..24) { |n| n*n}    # {400, 169, 225}

Метод reject — полная противоположность select. Он исключает из массива элементы, для которых блок возвращает значение true. Имеется также вариант reject! для модификации массива «на месте»:

с = [5, 8, 12, 9, 4, 30]
d = с.reject {|e| е % 2 == 0} # [5, 9]
b.reject! {|e| е % 3 == 0}
# с равно [5, 8, 4]

Методы min и max ищут минимальное и максимальное значение в массиве. У каждого метода есть две формы. В первой используется сравнение «по умолчанию», что бы это ни означало в конкретной ситуации (на базе оператора <=>). Во второй форме применяется блок для выполнения нестандартного сравнения.

а = %w[Elrond Galadriel Aragorn Saruman Legolas]
b = a.min # "Aragorn"
с = a.max # "Saruman"
d = a.min {|x,y| x.reverse <=> y.reverse} # "Elrond"
e = a.max {|x,y| x.reverse <=> y.reverse} # "Legolas"

Чтобы найти индекс минимального или максимального элемента (в предположении, что такой элемент один), применяется метод index:

# Продолжение предыдущего примера...
i = a.index a.min # 2
j = a.index a.max # 3

Такую же технику можно использовать и в других похожих ситуациях. Однако, если элемент не единственный, то будет найден только первый.

Оглавление книги

Оглавление статьи/книги

Генерация: 1.244. Запросов К БД/Cache: 3 / 0
поделиться
Вверх Вниз