Ruby/Подробнее об ассоциативных массивах: различия между версиями

Содержимое удалено Содержимое добавлено
м орфография, викификатор
м <source> -> <syntaxhighlight> (phab:T237267)
Строка 10:
Давайте создадим хеш, где в качестве ключа будем использовать целое число:
 
<sourcesyntaxhighlight lang="ruby">hash = {5=>3, 1=>6, 3=>2}
hash[5] #=> 3
hash[2] #=> nil это значит, что объект отсутствует
hash[3] #=> 2</sourcesyntaxhighlight>
 
А вот так будет выглядеть та же самая программа, если мы будем использовать массив:
 
<sourcesyntaxhighlight lang="ruby">array = [nil, 6, nil, 2, nil, 3]
array[5] #=> 3
array[2] #=> nil
array[3] #=> 2</sourcesyntaxhighlight>
 
'''Первый случай применимости хеша:''' если в массиве намечаются обширные незаполненные (то есть заполненные <code>nil</code>) области, то целесообразнее использовать хеш с целочисленным индексом.
Строка 28:
Продолжим поиски случаев применимости хеша и на этот раз подсчитаем, сколько раз каждое число повторяется в данном целочисленном массиве. Решение массивом:
 
<sourcesyntaxhighlight lang="ruby">array = [1, 2, 1, 2, 3, 2, 1, 2, 4, 5]
array.uniq.map{ |i| [i, array.find_all{ |j| j == i }.size] } #=> [[1, 3], [2, 4], [3, 1], [4, 1], [5, 1]]</sourcesyntaxhighlight>
 
Алгоритм получается ужасным. Не буду утомлять излишними терминами, а замечу, что по одному и тому же массиву итераторы (в количестве двух штук) пробегают много раз. А ведь достаточно одной «пробежки». Понятное дело, что такая программа не сделает вам чести. В качестве упражнения, предлагаю вам решить эту задачу другим, более оптимальным, способом.
Строка 35:
Теперь рассмотрим решение этой же задачи, но с применением хеша:
 
<sourcesyntaxhighlight lang="ruby">
array = [1, 2, 1, 2, 3, 2, 1, 2, 4, 5]
array.inject(Hash.new{ 0 }){ |result, i|
result[i] += 1
result
} #=> {5=>1, 1=>3, 2=>4, 3=>1, 4=>1}</sourcesyntaxhighlight>
 
Удалось избавиться от лишних методов и обойтись лишь одной «пробежкой» итератора по массиву.
Строка 54:
Теперь представим, что мы работаем системными администраторами. У нас есть список [[w:DNS|DNS]]-имён и [[w:IP-адрес|IP-адреса]]. Каждому DNS-имени соответствует только один IP-адрес. Как нам это соответствие записать в виде программы? Попробуем это сделать при помощи массива:
 
<sourcesyntaxhighlight lang="ruby">array = [["comp1.mydomen.ru", "192.168.0.3"],
["comp2.mydomen.ru", "192.168.0.1"],
["comp3.mydomen.ru", "192.168.0.2"]]</sourcesyntaxhighlight>
 
Всё бы ничего, но чтобы найти IP-адрес по DNS имени, придётся перелопатить весь массив в поиске нужного DNS:
 
<sourcesyntaxhighlight lang="ruby">dns_name = "comp1.mydomen.ru"
array.find_all{ |key, value| key == dns_name }[0][-1] #=> "192.168.0.3"</sourcesyntaxhighlight>
 
В данном примере было использовано два интересных приёма:
Строка 67:
* Если в двумерном массиве заранее известное количество столбцов (в нашем случае — два), то каждому из столбцов (в рамках любого итератора) можно дать своё имя (в нашем случае: <code>key</code> и <code>value</code>). Если бы мы такого имени не давали, то вышеописанное решение выглядело бы так:
 
<sourcesyntaxhighlight lang="ruby">array.find_all{ |array| array[0] == dns_name }[0][-1] #=> "192.168.0.3"</sourcesyntaxhighlight>
 
Без именования столбцов, внутри итератора вы будете работать с массивом (в двумерном массиве каждый элемент — массив, а любой итератор «пробегает» массив поэлементно). Это высказывание действительно, когда «пробежка» осуществляется по двумерному массиву.
Строка 75:
Теперь ту же самую задачу решим, используя хеш:
 
<sourcesyntaxhighlight lang="ruby">hash = {"comp1.mydomen.ru"=>"192.168.0.3",
"comp2.mydomen.ru"=>"192.168.0.1",
"comp3.mydomen.ru"=>"192.168.0.2"}
hash["comp1.mydomen.ru"] #=> "192.168.0.3"</sourcesyntaxhighlight>
 
Нет ни одного итератора и, следовательно, не сделано ни одной «пробежки» по массиву.
Строка 88:
В заключении, как и было обещано, приводится решение задачи с использованием метода <code>.update</code>:
 
<sourcesyntaxhighlight lang="ruby">array = [1, 2, 1, 2, 3, 2, 1, 2, 4, 5]
array.inject({}){ |result, i| result.update({ i=>1 }){ |key, old, new| old+new }}
#=> {5=>1, 1=>3, 2=>4, 3=>1, 4=>1}</sourcesyntaxhighlight>
 
Описание метода <code>.update</code> будет дано ниже. На данном этапе попытайтесь угадать принцип работы метода <code>.update</code>.
Строка 99:
Если состояние объектов-ключей изменилось, то хешу необходимо вызвать метод <code>.rehash</code>.
 
<sourcesyntaxhighlight lang="ruby">array1 = ["а", "б"]
array2 = ["в", "г"]
hash = {array1=>100, array2=>300}
Строка 106:
hash[array1] #=> nil
hash.rehash #=> {["я", "б"]=>100, ["в", "г"]=>300}
hash[array1] #=> 100</sourcesyntaxhighlight>
 
В данном примере ключами хеша (<code>hash</code>) являются два массива (<code>array1</code> и <code>array2</code>). Одному из них (<code>array1</code>) мы изменили нулевой элемент (с <code>"а"</code> на <code>"я"</code>). После этого доступ к значению был потерян. После выполнения метода <code>.rehash</code> всё встало на свои места.
Строка 112:
Как Ruby отслеживает изменение ключа в ассоциативном массиве? Очень просто: с помощью метода <code>.hash</code>, который генерирует «контрольную сумму» объекта в виде целого числа. Например:
 
<sourcesyntaxhighlight lang="ruby">[1, 2, 3].hash #=> 25</sourcesyntaxhighlight>
 
=== Способы создания ассоциативного массива ===
Строка 126:
Положим, что у нас в наличии индексный массив, где ключ и значение записаны последовательно. Тогда мы можем использовать связку методов <code>*</code> и <code>Hash[]</code>:
 
<sourcesyntaxhighlight lang="ruby">array = [1, 4, 5, 3, 2, 2]
Hash[*array] #=> {1=>4, 5=>3, 2=>2}</sourcesyntaxhighlight>
 
Элементы, стоящие на ''нечётной'' позиции (в данном случае: 1, 5 и 2) стали ключами, а элементы, стоящие на ''чётной'' позиции (то есть: 4, 3 и 2), стали значениями.
Строка 134:
Если повезло меньше и нам достался двумерный массив с элементами вида <code>[["ключ_1", "значение_1"], ["ключ_2", "значение_2"], ["ключ_3", "значение_3"], …]</code>, то его надо сплющить (<code>.flatten</code>) и тем задача будет сведена к предыдущей:
 
<sourcesyntaxhighlight lang="ruby">array = [[1, 4], [5, 3], [2, 2]]
Hash[*array.flatten] #=> {1=>4, 5=>3, 2=>2}</sourcesyntaxhighlight>
 
Каждый нулевой элемент подмассива станет ключом, а каждый первый — значением.
Строка 141:
Но может случиться так, что двумерный массив будет состоять из двух подмассивов: подмассива ключей и подмассива значений:
 
<sourcesyntaxhighlight lang="ruby">[["ключ_1", "ключ_2", "ключ_3", …], ["значение_1", "значение_2", "значение_3", …]]</sourcesyntaxhighlight>
 
Вспоминаем методы работы с массивами. Там был метод <code>.transpose</code> (транспонирование массива), вызов которого сведёт задачу к предыдущей.
 
<sourcesyntaxhighlight lang="ruby">array = [[1, 5, 2], [4, 3, 2]]
Hash[*array.transpose.flatten] #=> {1=>4, 5=>3, 2=>2}</sourcesyntaxhighlight>
 
==== Нет данных ====
Если нет данных, то лучше записать хеш как пару фигурных скобок:
 
<sourcesyntaxhighlight lang="ruby">hash = {}
hash[1] = 4
hash[5] = 3
hash[2] = 2
hash #=> {1=>4, 5=>3, 2=>2}</sourcesyntaxhighlight>
 
И уже по ходу дела разобраться, что к чему.
Строка 162:
Сведения о типе значений использовать следует так: создать хеш, в котором будет определён элемент по умолчанию. Элементом по умолчанию должен быть нулевой элемент соответствующего типа, то есть для строки это будет пустая строка (<code>""</code>), для массива — пустой массив (<code>[]</code>), а для числа — нуль (<code>0</code> или <code>0.0</code>). Это делается, чтобы к пустому элементу можно было что-то добавить и при этом не получить ошибку.
 
<sourcesyntaxhighlight lang="ruby">hash = Hash.new("")
hash["песенка про зайцев"] += "В тёмно-синем лесу, "
hash["песенка про зайцев"] += "где трепещут осины"
hash #=> {"песенка про зайцев"=>"В темно-синем лесу, где трепещут осины"}</sourcesyntaxhighlight>
 
Или ещё пример:
 
<sourcesyntaxhighlight lang="ruby">hash = Hash.new(0)
hash["зарплата"] += 60
hash["зарплата"] *= 21
hash #=> {"зарплата"=>1260}</sourcesyntaxhighlight>
 
Но, как известно, из любого правила есть исключение: использовать нулевой элемент, когда значение будет записываться умножением, нежелательно. Потому как, даже не будучи пророком, можно предсказать результат. Он будет равен нулю.
Строка 179:
Если вам изначально известны все ключи и значения, то и записывайте их сразу в виде хеша, одним из способов:
 
<sourcesyntaxhighlight lang="ruby">
{"март"=>400, "январь"=>350, "февраль"=>200} #=> на выходе такой же текст
{fox: 1, wolf: 2, dragon: 3} #=> {:fox=>1, :wolf=>2, :dragon=>3} обратите внимание на знак ':', он говорит что fox - это не строка,
# а чтото вроде перечисления (Enum), как в языке Си.
</syntaxhighlight>
</source>
 
Не изобретайте [[w:Велосипед|велосипед]] и поступайте как можно проще.
Строка 193:
Для получения отдельно массива ключей или значений существуют методы <code>.keys</code> и <code>.values</code>.
 
<sourcesyntaxhighlight lang="ruby">{1=>4, 5=>3, 2=>2}.keys #=> [1, 2, 5]
{1=>4, 5=>3, 2=>2}.values #=> [4, 3, 2]</sourcesyntaxhighlight>
 
Ассоциативные массивы в Ruby неупорядоченны: массивы могут иметь любой порядок элементов.
Строка 201:
Чтобы поменять местами ключи и значения ассоциативного массива, следует применять метод <code>.invert</code>. Этот метод возвращает ассоциативный массив с ключами, заменёнными значениями, и значениями, заменёнными ключами.
 
<sourcesyntaxhighlight lang="ruby">hash = {"первый ключ"=>4, "второй ключ"=>5}
hash.invert #=> {4=>"первый ключ", 5=>"второй ключ"}</sourcesyntaxhighlight>
 
Поскольку ключи в ассоциативных массивах уникальны, то ключи с одинаковыми значениями будут отброшены:
 
<sourcesyntaxhighlight lang="ruby">hash = {"первый ключ"=>10, "второй ключ"=>10}
hash.invert #=> {10=>"второй ключ"}</sourcesyntaxhighlight>
 
Небольшая хитрость: <code>hash.invert.invert</code> возвратит нам хеш с уникальными значениями.
Строка 214:
Что вы делаете, если хотите обновить какую-то программу или игру? Правильно, устанавливаете апдейт. Вы не поверите, но для обновления значения в ассоциативном массиве используется метод <code>.update</code>. Странно, да? Пример использования этого метода в «боевых» условиях мы уже приводили в начале раздела. Если вы помните, то мы считали, ''сколько раз повторяется каждое число''. Наверняка, вы немного подзабыли его решение (у программистов есть привычка не помнить [[w:Константа|константы]]). Позволю себе его вам напомнить:
 
<sourcesyntaxhighlight lang="ruby">
array = [1, 2, 1, 2, 3, 2, 1, 2, 4, 5]
array.inject({}){ |result, i| result.update({i=>1}){ |key, old, new| old + new } }
#=> {5=>1, 1=>3, 2=>4, 3=>1, 4=>1}</sourcesyntaxhighlight>
 
Страшноватая запись. Поэтому будем разбирать её по частям.
 
<sourcesyntaxhighlight lang="ruby">result.update({i=>1}){ |key, old, new| old + new }</sourcesyntaxhighlight>
 
Сразу после названия метода (в нашем случае <code>.update</code>) идёт передача параметра. Страшная запись <code>{i=>1}</code> — это не что иное, как ещё один хеш. Ключ его хранится в переменной <code>i</code> (счётчик итератора <code>.inject</code>), а в качестве значения выбрана единица. Зачем? Расскажу чуть позже.
Строка 231:
Здесь вроде бы все понятно. Запись стала менее страшной, но всё равно вызывает дрожь. Будем это исправлять!
 
<sourcesyntaxhighlight lang="ruby">… { |key, old, new| … } …</sourcesyntaxhighlight>
 
Раньше мы не встречались с такой записью. Но ничего страшного в ней нет. Это что-то вроде ''по́ля боя''. Нам выдали вооружение и необходимо провести некий манёвр. В нашем случае, [[w:Арсенал|арсенал]] у нас внушительный: <code>key</code>, <code>old</code> и <code>new</code>. Бой начинается при некоторых условиях. Наш бой начнется, когда при добавлении очередной пары (переданной в предыдущей части страшной записи) обнаружится, что такой ключ уже есть в хеше. Нам предлагается описать наши действия именно в таком случае. Что же это за действия?
 
<sourcesyntaxhighlight lang="ruby">… { … old + new } …</sourcesyntaxhighlight>
 
Всего лишь сложение <code>old</code> и <code>new</code>. Ничего не говорит? Тогда расскажу, что значат переменные <code>key</code>, <code>old</code> и <code>new</code>. В переменную <code>key</code> передаётся значение текущего ключа, в <code>old</code> — старое значение ключа ({{англ|old}} — старый), а в переменную <code>new</code> — добавляемое значение ключа ({{англ|new}} — новый).
Строка 248:
Для слияния двух массивов используется метод <code>.merge</code> или <code>.merge!</code>:
 
<sourcesyntaxhighlight lang="ruby">
hash1 = {3 => "a", 4 => "c"}
hash2 = {5 => "r", 7 => "t"}
hash1.merge!(hash2) #=> {5=>"r", 7=>"t", 3=>"a", 4=>"c"}</sourcesyntaxhighlight>
 
Если во втором массиве ключ будет совпадать с каким-либо ключем из первого массива, значение будет заменено на значение из второго массива.
Строка 258:
Ну вот, с новичками мы познакомились, теперь можно переходить к старым знакомым. Помните, как мы находили размер массива? Вот и с хешами точно также:
 
<sourcesyntaxhighlight lang="ruby">
hash = {5=>1, 1=>3, 2=>4, 3=>1, 4=>1}
hash.size #=> 5</sourcesyntaxhighlight>
 
Стоит уточнить, что если в индексных массивах под размером понимается количество элементов, то в ассоциативном массиве это количество пар вида <code>ключ=>значение</code>. В остальном же это наш старый добрый <code>.size</code>.
Строка 267:
О том, как добавлять элементы в массив мы знаем, а вот про удаление — нет. Необходимо это исправить. Чем мы сейчас и займёмся.
 
<sourcesyntaxhighlight lang="ruby">
hash = {5=>1, 1=>3, 2=>4, 3=>1, 4=>1}
hash.delete(5) #=> 1
hash #=> {1=>3, 2=>4, 3=>1, 4=>1}
hash.delete(5) #=> nil</sourcesyntaxhighlight>
 
Как вы, наверно, уже догадались, удалением пары по ключу занимается метод <code>.delete</code>. Ему передаётся ключ от пары, которую следует удалить.
Строка 284:
Давайте посмотрим его в действии:
 
<sourcesyntaxhighlight lang="ruby">hash = {5=>3, 1=>6, 3=>2}
hash.shift #=> [5, 3]
hash #=> {1=>6, 3=>2}</sourcesyntaxhighlight>
 
Обратите внимание, что метод <code>.shift</code> возвращает удаляемую пару в виде индексного массива <code>[ключ, значение]</code>.
Строка 301:
Чтобы преобразовать ассоциативный массив в индексный, надо использовать метод <code>to_a</code>. Его используют все, кто не может запомнить методов работы с хешами.
 
<sourcesyntaxhighlight lang="ruby">hash = {"гаечный ключ"=>10, "разводной ключ"=>22}
hash.to_a #=> [["гаечный ключ", 10], ["разводной ключ", 22]]</sourcesyntaxhighlight>
 
Способ преобразования таков. Сперва пары (ключ=>значение) преобразуются в массив:
 
<sourcesyntaxhighlight lang="ruby">{["гаечный ключ"=>10], ["разводной ключ"=>22]}</sourcesyntaxhighlight>
 
Затем «стрелку» заменяем на запятую:
 
<sourcesyntaxhighlight lang="ruby">{["гаечный ключ", 10], ["разводной ключ", 22]}</sourcesyntaxhighlight>
 
и фигурные скобки выпрямляем, так что теперь их можно заправить в стэплер.
 
<sourcesyntaxhighlight lang="ruby">[["гаечный ключ", 10], ["разводной ключ", 22]]</sourcesyntaxhighlight>
 
==== Упорядочение хеша ====
Да, множество пар в хеше неупорядоченно. Но это можно исправить, разве что результат потом будет не хешем, а двумерным массивом.
 
<sourcesyntaxhighlight lang="ruby">hash = {"гаечный ключ"=>4, "разводной ключ"=>10}
hash.sort #=> [["гаечный ключ", 4], ["разводной ключ", 10]]</sourcesyntaxhighlight>
 
В методе <code>.sort_by</code> передаются два значения:
 
<sourcesyntaxhighlight lang="ruby">hash = {"гаечный ключ"=>4, "разводной ключ"=>10}
hash.sort_by{ |key, value| value } #=> [["гаечный ключ", 4], ["разводной ключ", 10]]</sourcesyntaxhighlight>
 
Здесь мы упорядочили хеш по значению.
Строка 334:
Максимальная пара в хеше ищется точно также, как и максимальный элемент в массиве
 
<sourcesyntaxhighlight lang="ruby">hash = {"гаечный ключ"=>10, "разводной ключ"=>22}
hash.max #=> ["разводной ключ", 22]
hash.min #=> ["гаечный ключ" , 10]</sourcesyntaxhighlight>
 
но с небольшими особенностями:
Строка 345:
Несколько больше возможностей приобрели методы <code>max_by</code> и <code>min_by</code>:
 
<sourcesyntaxhighlight lang="ruby">
hash = {"гаечный ключ"=>10, "разводной ключ"=>22}
hash.max_by{ |key, value| value } #=> ["разводной ключ", 22]
hash.min_by{ |array| array[0] } #=> ["гаечный ключ" , 10]</sourcesyntaxhighlight>
 
Также, как и в методе <code>sort_by</code> есть возможность по разному получать текущую пару: в виде массива или двух переменных.
Строка 374:
Зададим вопрос «Хеш пустой?», но используя известный нам [[w:Лексикон|лексикон]]. Для начала спросим «Пустой хеш тебе не брат-близнец?»
 
<sourcesyntaxhighlight lang="ruby">empty_hash = {}
filled_hash = {"гаечный"=>20, "замочный"=>"английский", "разводной"=>34}
 
empty_hash == {} #=> true
filled_hash == {} #=> false</sourcesyntaxhighlight>
 
Можно спросить по другому: «Размер у тебя не нулевой?»
 
<sourcesyntaxhighlight lang="ruby">
empty_hash = {}
filled_hash = {"гаечный"=>20, "замочный"=>"английский", "разводной"=>34}
 
empty_hash .size.zero? #=> true
filled_hash.size.zero? #=> false</sourcesyntaxhighlight>
 
Но давайте будем задавать правильные вопросы
 
<sourcesyntaxhighlight lang="ruby">
empty_hash = {}
filled_hash = {"гаечный"=>20, "замочный"=>"английский", "разводной"=>34}
 
empty_hash .empty? #=> true
filled_hash.empty? #=> false</sourcesyntaxhighlight>
 
а то ещё примут нас за приезжих…
Строка 405:
Если вам нужно узнать у хеша ответ на вопрос «есть у тебя такой ключ?», но вы не знаете как это правильно спросить, то скорее всего вы зададите вопрос в два этапа: «какие ключи у тебя есть?» и «есть среди них такой ключ?»
 
<sourcesyntaxhighlight lang="ruby">pocket = {"гаечный"=>20, "замочный"=>"английский", "разводной"=>34}
pocket.keys.include?("гаечный") #=> true</sourcesyntaxhighlight>
 
В данном примере у нас в <code>pocket</code> нашёлся <code>"гаечный"</code> ключ.
Строка 412:
Но лучше задавать вопрос напрямую, это покажет ваше прекрасное знание языка.
 
<sourcesyntaxhighlight lang="ruby">pocket = {"гаечный"=>20, "замочный"=>"английский", "разводной"=>34}
pocket.key?("гаечный") #=> true</sourcesyntaxhighlight>
 
или в стиле индексных массивов
 
<sourcesyntaxhighlight lang="ruby">pocket = {"гаечный"=>20, "замочный"=>"английский", "разводной"=>34}
pocket.include?("гаечный") #=> true</sourcesyntaxhighlight>
 
Это несколько сократит первоначальное предложение, но тогда можно перепутать хеш с массивом.
Строка 427:
Давайте подумаем, как задать вопрос «есть такое значение?» хешу. Скорее всего, мы опять зададим вопрос в два этапа: «какие значения есть?» и «есть ли среди них нужное нам?»
 
<sourcesyntaxhighlight lang="ruby">pocket = {"гаечный"=>20, "замочный"=>"английский", "разводной"=>34}
pocket.values.include?("гаечный") #=> false — ой, забыл сменить
pocket.values.include?("английский") #=> true</sourcesyntaxhighlight>
 
Но [[w:Коренные народы|аборигены]] говорят иначе и задают вопрос напрямую:
 
<sourcesyntaxhighlight lang="ruby">pocket = {"гаечный"=>20, "замочный"=>"английский", "разводной"=>34}
pocket.value?("английский") #=> true</sourcesyntaxhighlight>
 
Задать вопрос «Есть такое значение?» можно не только при помощи метода <code>.value?</code>, но и при помощи более длинного <code>.has_value?</code>.
Строка 454:
Рассматривать заново работу каждого итератора в отдельности скучно. Поэтому мы будем рассматривать работу всех итераторов сразу.
 
<sourcesyntaxhighlight lang="ruby">hash = {"гаечный ключ"=>4, "разводной ключ"=>10}
 
hash.find_all{ |array| array[1] < 5 }
Строка 463:
 
hash.inject(0){ |result, array| result + array[1] }
#=> 14</sourcesyntaxhighlight>
 
Обратите внимание на то, что в качестве счётчика передаётся массив из двух элементов. В наших примерах счётчик итератора мы назвали <code>array</code>. В своих программах вы вольны называть его как угодно.
Строка 471:
Теперь посмотрим, как можно развернуть <code>array</code> в две переменные. Делается это простой заменой <code>array</code> на <code>key, value</code>:
 
<sourcesyntaxhighlight lang="ruby">hash = {"гаечный ключ"=>4, "разводной ключ"=>10}
 
hash.find_all{ |key, value| value < 5 }
Строка 480:
 
hash.inject(0){ |result, key, value| result + value }
#=> Ошибка в методе "+": невозможно сложить nil и число типа Fixnum</sourcesyntaxhighlight>
 
Обратите внимание, что развёртка массива прошла успешно только в первых двух итераторах. В третьем возникла ошибка. Давайте выясним, откуда там взялся <code>nil</code>. Дело в том, что развернуть массив не удалось, и теперь он стал называться не <code>array</code>, а <code>key</code>. Переменная <code>value</code> осталась «не у дел», и ей присвоилось значение <code>nil</code>. Чтобы это исправить, достаточно поставить круглые скобки:
 
<sourcesyntaxhighlight lang="ruby">hash.inject(0){ |result, (key, value)| result + value }
#=> 14</sourcesyntaxhighlight>
 
Ассоциативный массив, как и индексный массив, имеет метод <code>.map</code>, который передаёт замыканию ключ и соответствующее ему значение. При этом в замыкание на самом деле передаётся массив с ключом и значением, но Ruby «разворачивает» их в две переменные при передаче замыканию.
Строка 491:
Итератор <code>.map</code>, в свою очередь, возвращает индексный массив с результатами замыкания — по элементу массива на каждый ключ:
 
<sourcesyntaxhighlight lang="ruby">
hash = {"гаечный ключ"=>4, "разводной ключ"=>10}
hash.map { | key, value | "#{key} на #{value}" } #=> ["гаечный ключ на 4", "разводной ключ на 10"]
hash.map #=> [["гаечный ключ", 4], ["разводной ключ", 10]]</sourcesyntaxhighlight>
 
Итератор <code>.map</code>, вызванный без аргументов, аналогичен методу <code>.to_a</code>: просто раскладывает хеш в двумерный массив.
Строка 501:
Одному программисту надоело писать <code>hash["key"]</code> и он захотел сделать так, чтобы можно было написать <code>hash.key</code>.
 
<sourcesyntaxhighlight lang="ruby">
class Hash
def method_missing(id)
Строка 510:
hash = {"hello"=>"привет", "bye"=>"пока"}
hash.hello #=> "привет"
hash.bye #=> "пока"</sourcesyntaxhighlight>
 
Естественно, что ключи в таком хеше могут содержать только латиницу, символ подчёркивания и цифры (везде, кроме первого символа). Иначе говоря, удовлетворять всем требованиям, которые мы предъявляем к именам методов и именам переменных.