8.2.8. Копирование хэша в массив
Чтобы преобразовать весь хэш в массив, пользуйтесь методом to_a
. В получившемся массиве ключи станут элементами с четными индексами (начиная с 0), а значения — с нечетными:
h = {'а'=>1,'b'=>2}
h.to_a # ['а',1,'b',2]
Можно также получить массив, содержащий только ключи или только значения:
h.keys # ['а','b']
h.values # [1,2]
Наконец, можно поместить в массив только значения, соответствующие заданному списку ключей. Этот метод работает для хэшей примерно так же, как одноименный метод для массивов. (Кроме того, как и в случае массивов, метод values_at
заменяет устаревшие методы indices
и indexes
.)
h = {1=>'one', 2=>'two', 3=>'three', 4=>'four', 'cinco'=>'five'}
h.values_at(3,'cinco',4) # ['three','five','four']
h.values_at(1,3) # ['one','three']
8.2.9. Выборка пар ключ-значение по заданному критерию
К классу Hash
подмешан модуль Enumerable
, поэтому можно обращаться к методам detect
(find
), select
(find_all
), grep
, min
, max
и reject
(как и для массивов).
Метод detect
(синоним find
) находит одну пару ключ-значение. Он принимает блок (которому передается по одной паре за раз) и возвращает первую пару, для которой вычисление блока дает true
.
names = {'fred'=>'jones','jane'=>'tucker', 'joe'=>'tucker','mary'=>'SMITH'}
# Найти tucker.
names.detect {|k,v| v=='tucker' } # ['joe','tucker']
# Найти имена, записанные прописными буквами.
names.find {|k,v| v==v.upcase } # ['mary', 'SMITH']
Разумеется, объекты в хэше могут быть сколь угодно сложными, как и условие, проверяемое в блоке, но сравнение объектов разных типов может оказаться проблематичным.
Метод select
(синоним find_all
) возвращает все пары, удовлетворяющие условию, а не только первую:
names.select {|k,v| v=='tucker' }
# [['joe', 'tucker'], ['jane', 'tucker']]
names.find_all (|k,v| k.count('r')>0}
# [['mary', 'SMITH'], ['fred', 'jones']]
8.2.10. Сортировка хэша
Хэши по природе своей не упорядочены ни по ключам, ни по значениям. Чтобы отсортировать хэш, Ruby преобразует его в массив, который затем сортирует. Понятно, что и результатом является массив.
names = {'Jack'=>'Ruby','Monty'=>'Python',
'Blaise'=>'Pascal', 'Minnie'=>'Perl'} list = names.sort
# list равно:
# [['Blaise','Pascal'], ['Jack','Ruby'],
# ['Minnie','Perl'], ['Monty','Python']]
8.2.11. Объединение двух хэшей
Иногда бывает нужно объединить хэши. Метод merge
получает два хэша и формирует из них третий, перезаписывая обнаружившиеся дубликаты:
dict = {'base'=>'foundation', 'pedestal'=>'base'}
added = {'base'=>'non-acid', 'salt'=>'NaCl'}
new_dict = diet.merge(added)
# {'base' =>'non-acid', 'pedestal' =>'base', 'salt'=>'NaCl'}
У метода merge
есть синоним update
.
Если задан блок, то он может содержать алгоритм устранения коллизий. В нижеприведенном примере, если два ключа совпадают, в объединенном хэше остается меньшее значение (по алфавиту, по числовому значению или в каком-то ином смысле):
dict = {'base'=>'foundation', 'pedestal'=>'base'}
added = {'base'=>'non-acid', 'salt' =>'NaCl'}
new_dict = diet.merge(added) {|key,old,new| old < new ? old : new }
# {'salt'=>'NaCl', 'pedestal'=>'base', 'base'=>'foundation'}
Таким образом, при использовании блока результат может получиться не такой, как в случае, когда блок не задан. Имеются также методы merge!
и update!
, которые изменяют вызывающий объект «на месте».
8.2.12. Создание хэша из массива
Простейший способ сделать это — прибегнуть к способу создания хэшей с помощью квадратных скобок. Следующий способ годится, если массив состоит из четного числа элементов.
Array =[2,3,4,5,6,7]
hash = Hash[*array]
# hash равно: {2=>3, 4=>5, 6=>7}
8.2.13. Вычисление разности и пересечения хэшей
Ключи хэша можно скопировать в отдельный массив, а к получившимся из разных хэшей массивам применить методы &
и -
класса Array
. Результатом являются пересечение и разность множеств ключей. Соответствующие им значения можно получить с помощью метода each
, примененного к хэшу, содержащему все образованные таким способом ключи.
а = {'а'=>1,'b'=>2,'z'=>3}
b = {'x'=>99,'у'=>88,'z'=>77}
intersection = a.keys & b.keys