Всё про хэши в языке Руби — определение, примеры и методы

Пример использования хэша в реальном коде
Пример использования хэша в реальном коде

Это перевод оригинальной статьи от Jesus Castello.

Что такое хэш на языке Руби?

Хэш — это структура данных используемая для хранения данных в форме уникальных пар вида «ключ-значение». В отличие от массивов, хэши не имеют числовых индексов и доступ к значениям хэша осуществляется через ключи.

Например:

  • Список названий стран (значения) и соответствующих им международных кодов (ключи): RU→Россия, US→США
  • Словарь, в котором каждому слову (ключу) соответствуют его определения (значение)
  • Доменные имена (ключи) и их IP-адреса (значения)

Вы можете значительно ускорить ваш скрипт на Руби, используя хэши в правильных ситуациях.

Другими словами:

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

Как создать хэш?

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

Вот так:

{}

Это и есть пустой хэш!

Хэш с тремя парами ключ-значение:

{ a: 1, b: 2, c: 3 }

Здесь a это ключ, а 1 — соответствующее ему значение. Обратите внимание, что пары ключ-значение отделены друг от друга запятыми.

И теперь:

Давайте посмотрим, как использовать хэши с их основными методами в ваших проектах на Руби.

Запись новых значений в Руби-хэш

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

Другой пример:

fruits = { coconut: 1, apple: 2, banana: 3 }

А потом можно просто добавить новые значения в существующий хэш.

Как-то так:

fruits[:orange] = 4

Здесь :orange это ключ, а 4 — соответствующее ему значение.

Почему мы ставим двоеточие перед словом :orange когда мы получаем доступ к значению и после слова orange:, когда создаём хэш? Это так называемый синтаксический сахар, который позволяет создавать хэши без использования комбинации символов =>, являющейся более старым, но всё ещё валидным способом создать хэш.

Значениями хэша могут быть любые объекты Руби.

Включая:

  • Строки (String)
  • Целые и дробные числа (Integer и Float)
  • Массивы (Array)

Ключи тоже могут быть разных типов, но символы (Symbol, например — :banana) и строки (String) наиболее часто встречающиеся типы ключей.

Запомните, что:

Ключи всегда должны быть уникальными — в нашем хэше может быть только один ключ: orange или только один ключ: apple.Если вы добавляете один и тот же ключ дважды, вы просто меняете его значение.

Как получить доступ к значениям из хэша Руби?

Доступ к хэшу вы получаете по ключу.

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

Пример:

fruits[:orange] # 4

Смысл хэшей в этом и состоит: они обеспечивают мгновенный доступ к значению элемента по его ключу.

Если ключ не был создан, вы получите nil.

fruits[:peach] # nil

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

Пример:

fruits.fetch(:peach, 0)

Если вы будете использовать fetch без указания значения по умолчанию (второй аргумент) — Руби выбросит исключение KeyError.

Это может оказаться полезным для определения отсутствующих ключей.

Как объединить два Руби-хэша?

Вы можете взять два хэша и объединить их в новый хэш.

Какой метод подойдёт для этого?

Метод называется merge, что на английском означает: сливать, соединять, поглощать.

Вот как можно его использовать:

defaults = { a: 1, b: 2, c: 3 } preferences = { c: 4 } defaults.merge!(preferences) # {:a=>1, :b=>2, :c=>4}

Обратите внимание — вследствие того, что ключи уникальны, более новые значения заменят старые.

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

Примечание переводчика:

В примере был использован метод merge!, который перезаписывает вызвавший его объект, вместо того, чтобы создать действительно новый хэш. Если нужно этого избежать, используйте метод merge (без восклицательного знака). В этом случае полученный результат надо куда-то передать, иначе он не сохранится:

defaults = { a: 1, b: 2, c: 3 } preferences = { c: 4 } merged = defaults.merge(preferences) merged # {a=>1, b=>2, c=>4 } defaults # {a=>1, b=>2, c=>3 } preferences # {c=>4}

Если вам нужно лучше контролировать слияние ключей, вы можете передать в методы merge и merge! блок.

Например, такой:

defaults = { a: 1, b: 2, c: 5 } preferences = { a: 3, c: 4 } defaults.merge!(preferences) { |key, old, new| [old, new].max } # {:a=>3, :b=>2, :c=>5}

Где старые (old) значения берутся из defaults, а новые (new) из preferences.

Несколько значений для одного ключа

В словаре…

Слова уникальны, но все они могут иметь по несколько значений (определений).

И вы можете сделать то же самое на Руби!

Пример:

dictionary = { opportunity: [ "a set of circumstances that makes it possible to do something", "a situation or condition favorable for attainment of a goal" ], creativity: [ "the use of imagination or original ideas to create something new", "the ability to create", "the process where new ideas emerge from combining existing ideas in new ways" ] } dictionary[:creativity][1] # "the ability to create"

Где dictionary[:creativity] отдаёт вам массив, а [1] возвращает вам второй элемент из этого массива.

Другими словами:

Ключи — это символы (Symbol), а значения — массивы (Array). Когда вы обращаетесь к хэшу, вы получаете обратно массив, к которому вы можете обращаться, как и к любому другому массиву.

Как сортировать хэш?

Вы можете сортировать массивы. Но знали ли вы, что вы можете также сортировать и хэши?

Когда вы используете метод sort на хэше, он будет отсортирован по ключам.

Пример:

{ b: 1, a: 2 }.sort # [[:a, 2], [:b, 1]]

Но вы также можете отсортировать его по значениям:

{ c: 3, b: 1, a: 2 }.sort_by(&:last)

Вы, скорее всего, заметили, что после сортировки хэша вы получили совсем не хэш…

Это массив!

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

Получение всех ключей и значений из хэша

Если вы желаете получить список всех ключей хэша, то для вас хорошие новости — есть метод для этого!

Вот он:

{ apple: 1, banana: 2 }.keys # [:apple, :banana]

Есть также и метод, который вернёт вам массив, содержащий значения:

{ apple: 1, banana: 2 }.values # [1, 2]

Если вы хотите выяснить, был ли уже создан какой-нибудь ключ в хэше не получая массив ключей, используйте метод key?

Этот метод вернёт true или false в ответ.

Подведём итоги.

Вы узнали о хэшах Руби, полезной структуре данных, состоящей из пар ключ-значение. Также вы узнали, как получить из хэша значение по ключу и как сохранить новые данные в хэше.

Теперь откройте irb (или pry) и начинайте играть с хэшами, чтобы исследовать все их возможности!

Спасибо, что прочитали!

Начать дискуссию