Архив метки: хэши

Главная / хэши
1 Пост

Строки

Для начала поговорим о строках. Мы рассмотрим:

  • Различные виды строк, поддерживаемые Ruby
  • Многие методы, поддерживаемые String API
  • Символы

Строки с одной кавычкой очень буквальны. Они позволяют экранирование ' с помощью /, и показывают всё остальное практически как есть.

Строки с двойными кавычками имеют специальные символы, которые они могут интерпретировать: /n, /t и другие.
Другая интересная функция, которую они имеют, это интерполяцию строк.

Строки / интерполяция


single_quoted = 'ice cream \n followed by it\'s a party!'
double_quoted = "ice cream \n followed by it\'s a party!" 

puts single_quoted # => ice cream \n followed by it's a party!
puts double_quoted # => ice cream 
                   # =>   followed by it's a party! 

def multiply (one, two) 
  "#{one} умножить на #{two} равняется #{one * two}" # интерполяция доступна только для строк с двойными кавычками
end 
puts multiply(7, 3) 
# => 7 умножить на 3 равняется 21

Еще о строках:

  • Строковые методы, заканчивающиеся на !, изменяют существующую строку
    • Большинство других просто возвращают новую строку
  • Можно использовать %Q{длинная мультистрочная строка}
    • Ведет себя так же как и строка с двойными кавычками

my_name = " тим" 
puts my_name.lstrip.capitalize # => Тим
# методы без ! выводят измененную копию строки
p my_name # => " тим" 

my_name.lstrip! # убирает первый пробел
# метод с ! на самом деле изменяет строку

my_name[0] = 'К' # заменяет первый символ
puts my_name # => Ким 

cur_weather = %Q{Сегодня жарко
			     Захватите зонтики...} 

cur_weather.lines do |line| 
  line.sub! 'жарко', 'дождливо' # заменяет "жарко" на "дождливо"
  puts "#{line.strip}"
end 
# => Сегодня дождливо
# => Захватите зонтики...

API строк

https://ruby-doc.org/core-2.4.1/String.html

Здесь есть много хороших примеров.

strings пример

strings пример 2

Символы

Другой тип строк, который многих удивляет, — это идея символа.

Итак, что такое символ? Символ — это двоеточие, за которым следует некоторая строка.

К примеру, :foo-. Символы — это просто оптимизированные строки.

У них гораздо меньше методов, чем у (обычных) строк, и они действительно служат другой цели. Это постоянные имена, которые вам не нужно объявлять.

Символы гарантированно будут уникальными и неизменными. Они могут быть конвертированы в Строку с помощью to_s, или со Строки в Символ с помощью to_sym.

Символ может являться репрезентацией имени метода.

Так, к примеру, на любом объекте в Ruby вы можете просто спросить, какие у меня методы? И он предоставит вам все методы, поддерживаемые этим объектом.

irb методы

В этом случае мы делаем чуть больше, мы ищем методы со словом case.

Интересно, что мы видим обычную версию метода и версию с !, которая изменяет строку безвозвратно.

Массивы

Далее мы обсудим массивы (множества):

  • Как они создаются
  • Как изменять массивы
  • Доступ к элементам внутри массива

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

Массивы:

  • Коллекция ссылок на объекты
  • Индексируется с использованием оператора []
  • Может индексироваться с отрицательными числами или диапазонами
  • В одном массиве разрешается иметь различные типы данных
  • Можно использовать %w{str1 str2} для создания массива строк

het_arr = [1, "два", :три] # различные типы
puts het_arr[1] # => два (индексы массива начинаются с 0)

arr_words = %w{ какой же сегодня хороший день! }
puts arr_words[-2] # => хороший
puts "#{arr_words.first} - #{arr_words.last}" # => какой - день! 
p arr_words[-3, 2] # => ["сегодня", "хороший"] (вернуться на 3 элемента назад и взять 2 из них) 

# (Диапазон, который мы рассмотрим позже...)
p arr_words[2..4] # => ["сегодня", "хороший", "день!"] 

# Сделать строку из элементов массива, разделенных ','
puts arr_words.join(',') # => какой,же,сегодня,хороший,день!

Изменение массивов:

  • Добавление: push или <<
  • Удаление: pop или shift
  • Задать конкретный элемент: метод []=

Другие функции:

  • Показать случайный элемент(ы) с помощью sample
  • Сортировать или реверсировать массив с помощью sort! и reverse!

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

И аналогично строкам у вас есть либо сортировка без восклицательного знака, либо сортировка с ним. Как вы догадались, способ без ! возвращает отсортированную копию массива, а способ с ! изменяет сам массив.


# Вам нужен стек? Без проблем
stack = []; stack << "один"; stack.push ("два")
puts stack.pop # => два

# Вам нужна очередь? Тоже есть
queue = []; queue.push "один"; queue.push "два"
puts queue.shift # => один

a = [5,3,4,2].sort!.reverse! 
p a # => [5,4,3,2] (фактически изменяет массив) 
p a.sample(2) # => 2 случайных элемента

# Что будет, если добавить 33 как шестой (седьмой, считая с 0) элемент?
# Массив автоматически расширится и добавит nil вместо пустых элементов
a[6] = 33
p a # => [5, 4, 3, 2, nil, nil, 33]

Другие полезные методы:

  • each — перебирает массив
  • select — фильтрует массив, выбирая
  • reject — фильтрует массив, отклоняя
  • map — изменяет каждый элемент в массиве

API массивов.
Много других полезных методов можно найти, посмотрев API массивов: https://ruby-doc.org/core-2.4.1/Array.html

Давайте посмотрим некоторые примеры методов, которые я упомянул выше.


a = [1, 3, 4, 7, 8, 10]
a.each { |num| print num } # => 1347810 (нет новой строки)
puts # => (с новой строки)

new_arr = a.select { |num| num > 4 }
p new_arr # => [7, 8, 10]
new_arr = a.select { |num| num < 10 }
           .reject{ |num| num.even? }
p new_arr # => [1, 3, 7]

# Умножить каждый элемент на 3, создав новый массив
new_arr = a.map {|x| x * 3}
p new_arr # => [3, 9, 12, 21, 24, 30]

В итоге.
Таким образом, API массивов очень гибкий и очень мощный. Я просто показал несколько методов, но есть еще многие, которые могут быть полезными. И есть много способов обработки элементов.

Далее мы собираемся рассмотреть диапазоны.

Диапазоны

Поговорим о диапазонах и о том как они полезны в Ruby.

Итак, диапазоны — это по сути тип данных в Ruby, который используется для выражения естественных последовательностей.

  • 1..20, 'a' .. 'z'

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

К примеру, в 1..10 включается 1, включается 10 и, очевидно, всё что между ними.

Если используется три точки, к примеру 1...10, то последняя цифра исключается. То есть, в этом примере будет включено 1, включено 1-9, но 10 исключено.

Можно легко это запомнить как "чем больше точек у вас есть, тем меньше включено в конце". Хотя это слегка нелогично, но таким образом это легко запомнить.

Что такого особенного в диапазонах? Разве мы не можем сделать это с помощью массивов?

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

Кроме того:

  • Диапазоны очень эффективны
  • Могут быть конвертированы в массив с помощью to_a
  • Используются для условий и интервалов

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

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

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


some_range = 1..3
puts some_range.max # => 3
puts some_range.include? 2 # => true

puts (1...10) === 5.3 # => true
puts ('a'...'r') === "r" # => false (конец исключается)

p ('k'..'z').to_a.sample(2) # => ["k", "w"]
# или другой случайный массив с двумя буквами из диапазона

age = 55
case age
  when 0..12 then puts "Еще ребенок"
  when 13..99 then puts "Молод в душе!"
  else puts "Вы становитесь старше..."
end
# => Молод в душе!

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

Хэши

Теперь поговорим о хэшах.

Как они используются, зачем они используются, и есть ли у них схожести с блоками.

Хэши:

  • Индексированные коллекции ссылок на объекты
  • Создаются с помощью {} или Hash.new
  • Также известны как ассоциативные массивы
  • Индекс (ключ) может быть чем угодно
    • А не только целым числом, как в случае с массивами

Также:

  • Доступны с помощью оператора []
  • Значения задаются с помощью:
    • => (создание)
    • [] (после создания)

Давайте взглянем на пример.


editor_props = { "font" => "Arial", "size" => 12, "color" => "red"}

# Выше указан не блок, это хэш
puts editor_props.length # => 3
puts editor_props["font"] # => Arial

editor_props["background"] = "Blue"
editor_props.each_pair do |key, value|
  puts "Ключ: #{key}, значение: #{value}"
end
# => Ключ: font, value: Arial
# => Ключ: size, value: 12
# => Ключ: color, value: red
# => Ключ: background, value: Blue

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

Если хэш был создан с помощью Hash.new(0) (0 в качестве примера), то будет возвращен 0.


API хэшей.
API хэшей тоже полезно освоить: https://ruby-doc.org/core-2.4.1/Hash.html

К примеру, используя синтаксис Hash.new со значением 0, мы хотим рассчитать частоту слов. Скажем, у нас есть предложение с какими-то словами, каждое из которых повторяется дважды.


word_frequency = Hash.new(0)

sentence = "Chicka chicka boom boom"
sentence.split.each do |word|
  word_frequency[word.downcase] += 1
end

p word_frequency # => {"chicka" => 2, "boom" => 2}

Еще о хэшах

В текущей версии Ruby, порядок записей в хэшах сохраняется.

При использовании символов в качестве ключей, можно использовать синтаксис symbol:.

Если хэш является последним аргументом метода, {} являются опциональными.

Давайте взглянем на всё это в примере.


family_tree_19 = {самый_старший: "Джим", старший: "Джо", младший: "Джек"} # хэш
family_tree_19[:самый_младший] = "Джереми"
p family_tree_19
# => {:самый_старший=>"Джим", :старший=>"Джо", :младший=>"Джек“, :самый_младший => “Джереми”}
# порядок поддерживается


def adjust_colors (props = {foreground: "красный", background: "белый"})
  puts "Передний план: #{props[:foreground]}" if props[:foreground]
  puts "Фон: #{props[:background]}" if props[:background]
end
adjust_colors # => Передний план: красный
              # => Фон: белый
adjust_colors ({ :foreground => "зеленый" }) # => Передний план: зеленый
adjust_colors background: "желтый" # => Фон: желтый
adjust_colors :background => "фиолетовый" # => Фон: фиолетовый

Путаница между хэшами и блоками

Это происходит не слишком часто, но иногда начинающие разработчики допускают ошибку.


# Скажем, у вас есть хэш
a_hash = { :one => "one" }

# Затем вы выводите его
puts a_hash # => {:one=>"one"}

# Если вы попытаетесь сделать это за один шаг - вы получите SyntaxError
# puts { :one => "one" }

# Ruby путается и думает, что {} является блоком!!!

# Чтобы обойти это, вы можете использовать скобки
puts ({ :one => "one" }) # => {:one=>"one"}

# Или вообще отбросить {}... 
puts one: "one" # => {:one=>"one"}

В итоге.
Хэши являются индексированными коллекциями. Их использование очень похоже на использование массивов.

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