Чтение онлайн

на главную - закладки

Жанры

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

v

 end

 # Остальные методы опущены...

end

# He будет работать... для повторяющихся ключей

# актуально только последнее значение.

h = {1=>1, 2=>4, 3=>9, 4=>16, 2=>0}

# А так будет...

h = HashDup.new(1,1, 2,4, 3,9, 4,16, 2,0)

k = h.keys # [4, 1, 2, 2, 3]

v = h.values # [16, 1, 4, 0, 9]

n = h.size # 5

h.each {|k,v| puts "#{k} => #{v}"}

#
Печатается:

# 4 => 16

# 1 => 1

# 2 => 4

# 2 => 0

# 3 => 9

Но если не пользоваться литеральными хэшами, то задача решаема. В листинге 8.1 реализован класс, содержащий атрибут

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

Что должен возвращать метод

size
? Очевидно, «истинное» число пар ключ-значение, включая и дубликаты. Аналогично метод
keys
возвращает массив, который может содержать дубликаты. Итераторы ведут себя естественно; как и в случае обычного хэша, порядок обхода непредсказуем.

Помимо стандартного метода

delete
мы реализовали метод
delete_pair
. Первый удаляет все значения, ассоциированные с данным ключом, второй — только конкретную пару ключ-значение. (Отметим, что было бы затруднительно реализовать единственный метод вида
delete(k, v=nil)
, так как
nil
— допустимое значение в любом хэше.)

Для краткости мы не стали реализовывать весь класс целиком и, честно говоря, для некоторых методов, например

invert
, пришлось бы принимать небанальные решения по поводу желательного поведения. Интересующийся читатель может восполнить пробелы.

8.3. Перечисляемые структуры в общем

Что делает набор перечисляемым? Вообще-то сам тот факт, что это набор. Модуль

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

Кроме того, если предполагается пользоваться методами

min
,
max
и
sort
, то для набора должен быть определен метод сравнения (
<=>
). Все это достаточно очевидно.

Итак, перечисляемая структура представляет собой набор, в котором можно производить поиск, который можно обойти и, быть может, отсортировать. В любой определенный пользователем набор, не являющийся подклассом существующего

системного класса, имеет смысл подмешивать модуль
Enumerable
.

Имейте в виду — все сказанное о какой-то одной перечисляемой структуре относится ко всем. В качестве примеров таких структур можно назвать массив, хэш, дерево и т.д.

Конечно, у каждой структуры есть свои нюансы. Массив — это упорядоченный набор отдельных элементов, а хэш — неупорядоченный набор пар ключ-значение. Понятно, что в каких-то отношениях они будут вести себя по-разному.

Многие методы, с которыми мы познакомились при изучении массивов и хэшей (например,

map
и
find
), на самом деле определены в модуле
Enumerable
. Часто было трудно решить, как подать материал. Любая путаница или неточность — моя вина!..

Массив — наиболее часто употребляемый набор, подмешивающий этот модуль. Поэтому по умолчанию я буду пользоваться в примерах именно массивами.

8.3.1. Метод inject

Метод

inject
пришел в Ruby из языка Smalltalk (впервые он появился в версии Ruby 1.8). Его поведение интересно, хотя с первого раза понять его нелегко.

Он отражает тот факт, что мы часто хотим обойти список и по ходу «аккумулировать» некоторый результат. Конечно, самый естественный пример — суммирование чисел в списке. Но и для других операций обычно есть некий «аккумулятор» (которому присваивается начальное значение) и применяемая функция (в Ruby она представлена блоком).

В качестве тривиального примера рассмотрим массив чисел, которые нужно просуммировать:

nums = [3,5,7,9,11,13]

sum = nums.inject(0) {|x,n| x+n }

Обратите внимание, что начальное значение аккумулятора равно 0 («нейтральный элемент» для операции сложения). Затем блок получает текущее значение аккумулятора и значение текущего элемента списка. Действие блока заключается в прибавлении нового значения к текущей сумме.

Ясно, что этот код эквивалентен следующему:

sum = 0

nums.each {|n| sum += n }

В данном случае уровень абстракции лишь немногим выше. Если идея метода

inject
не укладывается у вас в голове, не пользуйтесь им. Но если удалось преодолеть первоначальное непонимание, то вы сможете найти ему новые элегантные применения.

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

sum = nums.inject {|x,n| x+n }

# To же самое, что:

sum = nums[0]

nums[1..-1].each {|n| sum + = n }

Другой похожий пример — вычисление произведения чисел. В данном случае аккумулятору следует присвоить начальное значение 1 (нейтральный элемент для операции умножения).

prod = nums.inject(1) {|x,n| x*n }

# или

prod = nums.inject {|x,n| x*n }

Поделиться:
Популярные книги

Идеальный мир для Лекаря 28

Сапфир Олег
28. Лекарь
Фантастика:
юмористическое фэнтези
аниме
фэнтези
5.00
рейтинг книги
Идеальный мир для Лекаря 28

Выдумщик (Сочинитель-2)

Константинов Андрей Дмитриевич
6. Бандитский Петербург
Детективы:
боевики
7.93
рейтинг книги
Выдумщик (Сочинитель-2)

Позывной "Князь" 3

Котляров Лев
3. Князь Эгерман
Фантастика:
попаданцы
аниме
фэнтези
5.00
рейтинг книги
Позывной Князь 3

Архонт

Прокофьев Роман Юрьевич
5. Стеллар
Фантастика:
боевая фантастика
рпг
7.80
рейтинг книги
Архонт

Божья коровка 2

Дроздов Анатолий Федорович
2. Божья коровка
Фантастика:
альтернативная история
5.00
рейтинг книги
Божья коровка 2

Паладин из прошлого тысячелетия

Еслер Андрей
1. Соприкосновение миров
Фантастика:
боевая фантастика
попаданцы
6.25
рейтинг книги
Паладин из прошлого тысячелетия

Антимаг его величества. Том VI

Петров Максим Николаевич
6. Модификант
Фантастика:
фэнтези
попаданцы
аниме
5.00
рейтинг книги
Антимаг его величества. Том VI

Мастер 9

Чащин Валерий
9. Мастер
Фантастика:
боевая фантастика
попаданцы
технофэнтези
аниме
фэнтези
5.00
рейтинг книги
Мастер 9

Законник Российской Империи

Ткачев Андрей Юрьевич
1. Словом и делом
Фантастика:
городское фэнтези
альтернативная история
аниме
5.00
рейтинг книги
Законник Российской Империи

Позывной "Князь" 2

Котляров Лев
2. Князь Эгерман
Фантастика:
фэнтези
попаданцы
аниме
5.00
рейтинг книги
Позывной Князь 2

Хозяин Стужи 3

Петров Максим Николаевич
3. Злой Лед
Фантастика:
аниме
фэнтези
попаданцы
7.00
рейтинг книги
Хозяин Стужи 3

Возмутитель спокойствия

Владимиров Денис
1. Глэрд
Фантастика:
фэнтези
боевая фантастика
попаданцы
5.00
рейтинг книги
Возмутитель спокойствия

Сводный гад

Рам Янка
2. Самбисты
Любовные романы:
современные любовные романы
эро литература
5.00
рейтинг книги
Сводный гад

Законы Рода. Том 10

Андрей Мельник
10. Граф Берестьев
Фантастика:
юмористическая фантастика
аниме
фэнтези
5.00
рейтинг книги
Законы Рода. Том 10