Поскольку ключи в хэше уникальны, такая операция может привести к потере данных. Значения-дубликаты будут преобразованы в уникальный ключ, которому соответствует какое-то одно из множества прежних значений. Предсказать, какое именно, невозможно.
8.2.7. Поиск ключей и значений в хэше
Определить, было ли присвоено значение некоторому ключу, позволяет метод
has_key?
или любой из его синонимов
include?
,
key?
,
member?
:
а = {"а"=>1,"b"=>2}
a.has_key? "с" # false
a.include? "а" # true
a.key? 2 # false
a.member? "b" # true
Можно
также воспользоваться методом
empty?
, чтобы узнать, остался ли в хэше хотя бы один ключ. А метод
length
и его синоним
size
позволяют узнать, сколько ключей имеется в хэше:
a.empty? # false
a.length # 2
Можно проверить также, существует ли указанное значение. Для этого предназначены методы
has_value?
или
value?
:
a.has_value? 2 # true
a.value? 99 # false
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"}
8.2.9. Выборка пар ключ-значение по заданному критерию
К классу
Hash
подмешан модуль
Enumerable
, поэтому можно обращаться к методам
detect
(
find
),
select
(
find_all
),
grep
,
min
,
max
и
reject
(как и для массивов).
Метод
detect
(синоним
find
) находит одну пару ключ-значение. Он принимает блок (которому передается по одной паре за раз) и возвращает первую пару, для которой вычисление блока дает
Разумеется, объекты в хэше могут быть сколь угодно сложными, как и условие, проверяемое в блоке, но сравнение объектов разных типов может оказаться проблематичным.
Метод
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) {|key,old,new| old < new ? old : new }
Таким образом, при использовании блока результат может получиться не такой, как в случае, когда блок не задан. Имеются также методы
merge!
и
update!
, которые изменяют вызывающий объект «на месте».
8.2.12. Создание хэша из массива
Простейший способ сделать это — прибегнуть к способу создания хэшей с помощью квадратных скобок. Следующий способ годится, если массив состоит из четного числа элементов.