Программирование на языке Ruby
Программирование на языке Ruby читать книгу онлайн
Внимание! Книга может содержать контент только для совершеннолетних. Для несовершеннолетних чтение данного контента СТРОГО ЗАПРЕЩЕНО! Если в книге присутствует наличие пропаганды ЛГБТ и другого, запрещенного контента - просьба написать на почту [email protected] для удаления материала
# Сравнить а и b а <=> bend# Теперь sorted равно:# [ "Star 69", "A Star is Born", "The Starr Report"# "Starship Troopers", "Star Wars"]Данный пример не слишком полезен и, конечно, его можно было бы записать более компактно. Но идея в том, что для сравнения двух операндов в определенном порядке над ними можно выполнять произвольно сложный набор операций. (Отметим, однако, что мы не изменили исходные операнды, так как работали с их копиями.) Эта общая техника полезна во многих ситуациях, например для сортировки по нескольким ключам или по ключам, вычисляемым во время выполнения.
В последних версиях Ruby в модуль
Enumerablesort_byArrayВ методе
sort_byВ качестве искусственного примера рассмотрим список файлов, который необходимо отсортировать по размеру. Прямолинейный способ выглядит так:
files = files.sort {|x,y| File.size(x) <=> File.size(y) }Однако тут есть две проблемы. Во-первых, слишком многословно. Надо бы сделать покомпактнее.
Во-вторых, при такой сортировке приходится многократно обращаться к диску, а это довольно дорогая операция (по сравнению с операциями в оперативной памяти). Хуже того, одна и та же операция может выполняться несколько раз.
Метод
sort_byfiles = files.sort_by {|x| File.size(x) }Здесь каждый ключ вычисляется ровно один раз, а затем сохраняется в виде пары ключ-данные. Для небольших массивов производительность при таком подходе может даже снизиться, зато код получается более понятным.
Не существует метода
sort_by!А как обстоит дело с сортировкой по нескольким ключам? Предположим, что имеется массив объектов, который нужно отсортировать по трем атрибутам: имени, возрасту и росту. Из того, что массивы можно сравнивать, следует, что такое решение будет работать:
list = list.sort_by {|x| [x.name, x.age, x.height] }Конечно, элементы массива могут быть и не такими простыми. Допустимы произвольно сложные выражения.
8.1.6. Выборка из массива по заданному критерию
Иногда нужно найти в массиве один или несколько элементов так, как будто мы опрашиваем таблицу в базе данных. Для этого есть несколько способов; рассмотренные ниже реализованы в подмешанном модуле
EnumerableМетод
detecttruex = [5, 8, 12, 9, 4, 30]# Найти первый элемент, кратный 6.x.detect {|e| e % 6 == 0 } #12# Найти первый элемент, кратный 7.c.detect {|e| e % 7 == 0 } # nilРазумеется, хранящиеся в массиве объекты могут быть произвольно сложными, равно как и условие, проверяемое в блоке.
Метод
finddetectfind_allselectfind_all# Продолжение предыдущего примера...x.find {|e| e % 2 == 0} # 8x.find_all {|e| e % 2 == 0} # [8, 12, 4, 30]x.select {|e| e % 2 == 0} # [8, 12, 4, 30]Метод
grep===grepg/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}Метод
rejectselecttruereject!с = [5, 8, 12, 9, 4, 30]d = с.reject {|e| е % 2 == 0} # [5, 9]b.reject! {|e| е % 3 == 0}# с равно [5, 8, 4]Методы
minmax<=>а = %w[Elrond Galadriel Aragorn Saruman Legolas]b = a.min # "Aragorn"с = a.max # "Saruman"
