Ruby/Подробнее об ассоциативных массивах: различия между версиями
Содержимое удалено Содержимое добавлено
Byzantine (обсуждение | вклад) м орфография, викификатор |
|||
Строка 1:
== Подробнее об ассоциативных массивах ==
Различают два типа массивов: индексные, у которых в качестве индекса только целое число, и ассоциативные, где индексом может быть любой объект.
Строка 25 ⟶ 24 :
'''Первый случай применимости хеша:''' если в массиве намечаются обширные незаполненные (то есть заполненные <code>nil</code>) области, то целесообразнее использовать хеш с целочисленным индексом.
Использовать хеш в данном случае лучше потому, что, формально, хеш для данного примера состоит из трёх значащих пар, а массив
Продолжим поиски случаев применимости хеша и на этот раз подсчитаем, сколько раз каждое число повторяется в данном целочисленном массиве. Решение массивом:
Строка 66 ⟶ 65 :
В данном примере было использовано два интересных приёма:
* Если в двумерном массиве заранее известное количество столбцов (в нашем случае
<source lang="ruby">array.find_all{ |array| array[0] == dns_name }[0][-1] #=> "192.168.0.3"</source>
Без именования столбцов, внутри итератора вы будете работать с массивом (в двумерном массиве каждый элемент
* Метод <code>.find_all</code> возвращает двумерный массив примерно следующего вида: <code><nowiki>[["comp1.mydomen.ru", "192.168.0.3"]]</nowiki></code>, чтобы получить строку <code>"192.168.0.3"</code> необходимо избавиться от двумерности. Делается это при помощи метода <code>[]</code>, который вызывается два раза (понижает размерность c двух до нуля). Метод <code>[0]</code> возвращает в результате
Теперь ту же самую задачу решим, используя хеш:
Строка 87 ⟶ 86 :
Вполне естественно, что существуют и другие случаи применимости хеша, но вероятность столкнуться с ними в реальной работе намного меньше. Вышеописанных трёх случаев должно хватить надолго.
В заключении, как и было
<source lang="ruby">array = [1, 2, 1, 2, 3, 2, 1, 2, 4, 5]
Строка 96 ⟶ 95 :
=== Что используется в качестве ключей? ===
В качестве ключей ассоциативного массива можно использовать любые типы. Например, другие ассоциативные массивы, строки, числа, символы или просто
▲В качестве ключей ассоциативного массива можно использовать любые типы. Например, другие ассоциативные массивы, строки, числа, символы или просто обьекты любых классов.
Если состояние объектов-ключей изменилось, то хешу необходимо вызвать метод <code>.rehash</code>.
Строка 112 ⟶ 110 :
В данном примере ключами хеша (<code>hash</code>) являются два массива (<code>array1</code> и <code>array2</code>). Одному из них (<code>array1</code>) мы изменили нулевой элемент (с <code>"а"</code> на <code>"я"</code>). После этого доступ к значению был потерян. После выполнения метода <code>.rehash</code> всё встало на свои места.
Как Ruby отслеживает изменение ключа в ассоциативном массиве? Очень просто: с помощью метода <code>.hash</code>, который генерирует «контрольную сумму»
<source lang="ruby">[1, 2, 3].hash #=> 25</source>
=== Способы создания ассоциативного массива ===
При создании ассоциативного массива важно ответить на несколько вопросов:
* Какие данные имеются?
* Какого типа эти данные?
* Что будет ключом, а что
Ответы определят способ создания хеша.
==== Из одномерного массива ====
Положим, что у нас в наличии индексный массив, где ключ и значение записаны последовательно. Тогда мы можем использовать связку методов <code>*</code> и <code>Hash[]</code>:
Строка 136 ⟶ 132 :
==== Из двумерного массива ====
Если повезло меньше и нам достался двумерный массив с элементами вида <code>[["ключ_1", "значение_1"], ["ключ_2", "значение_2"], ["ключ_3", "значение_3"], …]</code>, то его надо сплющить (<code>.flatten</code>) и тем задача будет сведена к предыдущей:
Строка 142 ⟶ 137 :
Hash[*array.flatten] #=> {1=>4, 5=>3, 2=>2}</source>
Каждый нулевой элемент подмассива станет ключом, а каждый первый
Но может случиться так, что двумерный массив будет состоять из двух подмассивов: подмассива ключей и подмассива значений:
Строка 154 ⟶ 149 :
==== Нет данных ====
Если нет данных, то лучше записать хеш как пару фигурных скобок:
Строка 166 ⟶ 160 :
==== Известен только тип значений ====
Сведения о типе значений использовать следует так: создать хеш, в котором будет определён элемент по умолчанию. Элементом по умолчанию должен быть нулевой элемент соответствующего типа, то есть для строки это будет пустая строка (<code>""</code>), для массива
▲Сведения о типе значений использовать следует так: создать хеш, в котором будет определён элемент по умолчанию. Элементом по умолчанию должен быть нулевой элемент соответствующего типа, то есть для строки это будет пустая строка (<code>""</code>), для массива — пустой массив (<code>[]</code>), а для числа — нуль (<code>0</code> или <code>0.0</code>). Это делается, чтобы к пустому элементу можно было что-то добавить и при этом не получить ошибку.
<source lang="ruby">hash = Hash.new("")
Строка 184 ⟶ 177 :
==== Всё известно и дано ====
Если вам изначально известны все ключи и значения, то и записывайте их сразу в виде хеша, одним из способов:
Строка 196 ⟶ 188 :
=== Методы работы с ассоциативными массивами ===
Когда речь пойдёт о методах, которые присутствуют в ассоциативных массивах, то частенько будет возникать чувство [[w:Дежавю|дежавю]]. Во всяком случае, учить заново итераторы вам не придётся. Вполне естественно, что появятся новички, но их будет немного. Тем не менее, прилежный преподаватель первым делом представляет новичков группе. Поэтому и мы начнем с тех методов, которые будут необходимы нам при работе с ассоциативными массивами, но отсутствуют у индексных.
==== Получение массива значений и массива ключей ====
Для получения отдельно массива ключей или значений существуют методы <code>.keys</code> и <code>.values</code>.
Строка 209 ⟶ 199 :
==== Замена ключей на значения ====
Чтобы поменять местами ключи и значения ассоциативного массива, следует применять метод <code>.invert</code>. Этот метод возвращает ассоциативный массив с ключами, заменёнными значениями, и значениями, заменёнными ключами.
Строка 223 ⟶ 212 :
==== Обновление пары ====
Что вы делаете, если хотите обновить какую-то программу или игру? Правильно, устанавливаете апдейт. Вы не поверите, но для обновления значения в ассоциативном массиве используется метод <code>.update</code>. Странно, да? Пример использования этого метода в
▲Что вы делаете, если хотите обновить какую-то программу или игру? Правильно, устанавливаете апдейт. Вы не поверите, но для обновления значения в ассоциативном массиве используется метод <code>.update</code>. Странно, да? Пример использования этого метода в "боевых" условиях мы уже приводили в начале раздела. Если вы помните, то мы считали, ''сколько раз повторяется каждое число''. Наверняка, вы немного подзабыли его решение (у программистов есть привычка не помнить [[w:Константа|константы]]). Позволю себе его вам напомнить:
<source lang="ruby">
Строка 235 ⟶ 223 :
<source lang="ruby">result.update({i=>1}){ |key, old, new| old + new }</source>
Сразу после названия метода (в нашем случае <code>.update</code>) идёт передача параметра. Страшная запись <code>{i=>1}</code>
Не обязательно писать именно <code>{i=>1}</code>. Можно «сократить» фигурные скобки и записать <code>i=>1</code>.
'''Счётчик итератора'''
Здесь вроде бы все понятно. Запись стала менее страшной, но всё равно вызывает дрожь. Будем это исправлять!
Строка 249 ⟶ 237 :
<source lang="ruby">… { … old + new } …</source>
Всего лишь сложение <code>old</code> и <code>new</code>. Ничего не говорит? Тогда расскажу, что значат переменные <code>key</code>, <code>old</code> и <code>new</code>. В переменную <code>key</code> передаётся значение текущего ключа, в <code>old</code>
Теперь переведём запись <code>old + new</code> на русский: в случае обнаружения ключа в хеше, нам необходимо сложить старое значение с новым. Если помните, то новое значение равняется единице, то есть в случае когда ключ, хранимый в <code>i</code> уже есть в хеше <code>result</code>, то к старому значению просто добавляется единица. Вот и всё… а вы боялись.
Строка 258 ⟶ 246 :
==== Слияние двух массивов ====
Для слияния двух массивов используется метод <code>.merge</code> или <code>.merge!</code>:
Строка 269 ⟶ 256 :
==== Размер ассоциативного массива ====
Ну вот, с новичками мы познакомились, теперь можно переходить к старым знакомым. Помните, как мы находили размер массива? Вот и с хешами точно также:
Строка 279 ⟶ 265 :
==== Удаление пары по ключу ====
О том, как добавлять элементы в массив мы знаем, а вот про удаление
▲О том, как добавлять элементы в массив мы знаем, а вот про удаление — нет. Необходимо это исправить. Чем мы сейчас и займёмся.
<source lang="ruby">
Строка 290 ⟶ 275 :
Как вы, наверно, уже догадались, удалением пары по ключу занимается метод <code>.delete</code>. Ему передаётся ключ от пары, которую следует удалить.
Метод <code>.delete</code> возвращает значение, которое соответствовало ключу в удаляемой паре. Если в хеше отсутствует пара с передаваемым ключом, то метод <code>.delete</code> возвращает <code>nil</code>. Напоминаем, что <code>nil</code>
==== Удаление произвольной пары ====
Многие программисты удивляются, когда узнаю́т, что ассоциативные массивы имеют метод <code>.shift</code>. Связано это удивление с тем, что у индексных массивов он удаляет первый элемент, возвращая его во время удаления. А вот как понять, какая пара является первой? И что такое первый в неупорядоченной последовательности пар?
Строка 309 ⟶ 293 :
==== Преобразовать в индексный массив ====
Чуть ранее уже говорилось, что в большинстве случаев индексные массивы удобней ассоциативных.
Строка 334 ⟶ 317 :
==== Упорядочение хеша ====
Да, множество пар в хеше неупорядоченно. Но это можно исправить, разве что результат потом будет не хешем, а двумерным массивом.
Строка 347 ⟶ 329 :
Здесь мы упорядочили хеш по значению.
Сначала хеш упорядочивается по ключам, а потом, в случаях равнозначных ключей при использовании <code>sort_by</code>,
==== Поиск максимальной/минимальной пары ====
Максимальная пара в хеше ищется точно также, как и максимальный элемент в массиве
Строка 359 ⟶ 340 :
но с небольшими особенностями:
* результат поиска
* сначала поиск происходит по ключу, а в случае равноправных ключей при использовании <code>max_by</code> и <code>min_by</code>
Несколько больше возможностей приобрели методы <code>max_by</code> и <code>min_by</code>:
Строка 372 ⟶ 353 :
=== Логические методы ===
Работа логических методов похожа на допрос с пристрастием. Помните, как в детективах во время теста на детекторе лжи, главный герой восклицал: «Отвечать только „да“ или „нет“!» Если перевести это на язык Ruby, то это будет звучать примерно так: «Отвечать только <code>true</code> или <code>false</code>!»
Строка 392 ⟶ 372 :
==== Хеш пустой? ====
Зададим вопрос «Хеш пустой?», но используя известный нам [[w:Лексикон|лексикон]]. Для начала спросим «Пустой хеш тебе не брат-близнец?»
Строка 424 ⟶ 403 :
==== Есть такой ключ? ====
Если вам нужно узнать у хеша ответ на вопрос «есть у тебя такой ключ?», но вы не знаете как это правильно спросить, то скорее всего вы зададите вопрос в два этапа: «какие ключи у тебя есть?» и «есть среди них такой ключ?»
Строка 447 ⟶ 425 :
==== Есть такое значение? ====
Давайте подумаем, как задать вопрос «есть такое значение?» хешу. Скорее всего, мы опять зададим вопрос в два этапа: «какие значения есть?» и «есть ли среди них нужное нам?»
Строка 462 ⟶ 439 :
=== Итераторы ===
У ассоциативных массивов есть следующие итераторы:
* <code>.find_all</code>
* <code>.map</code>
* <code>.inject</code>
Набор итераторов точно такой же, как и у индексных массивов
* Результатом является двумерный массив (как после метода <code>.to_a</code>).
Строка 513 ⟶ 489 :
Ассоциативный массив, как и индексный массив, имеет метод <code>.map</code>, который передаёт замыканию ключ и соответствующее ему значение. При этом в замыкание на самом деле передаётся массив с ключом и значением, но Ruby «разворачивает» их в две переменные при передаче замыканию.
Итератор <code>.map</code>, в свою очередь, возвращает индексный массив с результатами замыкания
<source lang="ruby">
Строка 523 ⟶ 499 :
=== Хитрости ===
Одному программисту надоело писать <code>hash["key"]</code> и он захотел сделать так, чтобы можно было написать <code>hash.key</code>.
Строка 540 ⟶ 515 :
=== Задачи ===
# Дан массив слов. Необходимо подсчитать, сколько раз встречается каждое слово в массиве.
|