Как стать автором
Поиск
Написать публикацию
Обновить

Покорим Ruby вместе! Капля пятая

Время на прочтение4 мин
Количество просмотров35K
Продолжаем (1, 2, 3, 4) штудировать Руби. На этот раз дело коснётся массивов. Но начнем с диапазонов.

Диапазоны значений


Иногда полезно иметь возможность сохранить «концепт» простого списка, причём хочется, чтобы объявить его мы могли бы максимально просто, например: список из букв от A до Z, или числа от 1 до 25. С помощью диапазонов это возможно, они в Руби максимально интуитивно понятны. Вот простые числовые диапазоны:

digits = 0..9
scale1 = 0..10
scale2 = 0...10 #digits = scale2


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

Массивы


Простые переменные порой не годятся для реального программирования. Каждый современный ЯП, в т.ч. и Руби, поддерживает более сложные формы структурированных данных. В Руби вы можете представлять упорядоченные наборы объектов с помощью массивов.

Массивы в Руби динамические: можно (но не обязательно) указывать размер массива при создании. После этого он может расти без участия со стороны программиста, поэтому в практике редко приходится даже узнавать его размер. Массивы в Руби гетерогенные: они могут хранить данные самых разных типов данных (если быть точным, то массив хранит только ссылки на объекты). Три одинаковых массива:

a = Array.[](1,2,3,4)
b = Array[1,2,3,4]
c = [1,2,3,4]


Для создания массивов используется специальный метод класса []. Также есть метод new, который берет 0, 1 или два параметра: первый — количество элементов, второй — их значение. Смотрим пример:

d = Array.new # Создаем пустой массив
e = Array.new(3) # [nil, nil, nil]
f = Array.new(3, "ruby") # ["ruby", "ruby", "ruby"]


Частая ошибка начинающих — считаем, что элементы независимы друг от друга. Однако, как было сказано раньше, в массиве лишь ссылки на один объект. Чтобы избежать такого поведения используем блок (мы его уже встречали во второй капле — это код между {}):

f[0].capitalize! # f теперь: ["Ruby", "Ruby", "Ruby"]
g = Array.new(3) { "ruby" } # ["ruby", "ruby", "ruby"]
g[0].capitalize! # g теперь: ["Ruby", "ruby", "ruby"]


Обращение к элементам и установление их значений выполняются с помощью методов [] и []= соответственно. Каждый может принимать один или два (начало и длина) параметра или диапазон. Обратный отсчет с конца массива начинается с -1. Считывать значения можно и специальным простым методом at — он принимает только один параметр и поэтому работает немного быстрее, delete_at удалит элемент. Смотрим:

a = [1, 2, 3, 4, 5, 6]
b = a[0] # 1
c = a.at(0) # 1
d = a[-2] # 5
e = a.at(-2) # 5
f = a[9] # nil
g = a.at(9) # nil
h = a[3,3] # [4, 5, 6]
i = a[2..4] # [3, 4, 5]
j = a[2...4] # [3, 4]

a[1] = 8 # [1, 8, 3, 4, 5, 6]
a[1,3] = [10, 20, 30] # [1, 10, 20, 30, 5, 6]
a[0..3] = [2, 4, 6, 8] # [2, 4, 6, 8, 5, 6]
a[-1] = 12 # [2, 4, 6, 8, 5, 12]

a.delete_at(3) # [1, 2, 4, 5, 6]
a.delete_at(9) # nil


Другой способ — толкание (pushing) данных. Метод join «сливает» элементы массива в одну переменную, в качестве параметра указываем разделитель:

x = []
x << "Word"
x << "Play" << "Fun"
puts x.join(', ') # Word, Play, Fun


Методы first и last возвращают первый и последний элемент массива соответственно, а values_at — массив, содержащий только выбранные элементы:

x = ["alpha", "beta", "gamma", "delta", "epsilon"]
a = x.first # alpha
b = x.values_at(0..2,4) # [alpha, beta, gamma, epsilon]


Метод length и его алиас size возвратят количество элементов в массиве, а nitems не будет считать пустые элементы (nil), compact уберёт nil из массива вообще:

y = [1, 2, nil, nil, 3, 4]
c = y.size # 6
e = y.nitems # 4
d = y.compact # [1, 2, 3, 4]


Самый простой метод для сортировки массива — это sort (попробуйте сами). Сортировка работает только в массивах, содержащих элементы, которые поддаются сравнению — с массивами со смешанными типами данных метод возвратит ошибку. Отсортируем смешанный массив, налету преобразовывая его элементы в строки (преобразовываем методом to_s):

a = [1, 2, "three", "four", 5, 6]
b = a.sort {|x,y| x.to_s <=> y.to_s}
# b теперь [1, 2, 5, 6, "four", "three"]


Как это работает? <=> — один из методов сравнения (см. третью каплю). Блок возвращает -1, если первый их сравниваемой пары элемент меньше (тогда метод меняет элементы местами), 0 если элементы равны, 1 — если больше (в последних двух случаях оставляем элементы на местах). Поэтому для убывающего порядка надо просто поменять местами сравниваемые элементы ({|x,y| y.to_s <=> x.to_s}). Думаю, что мы всё поняли.

Для выборки элементов из массива по критериям используем detect (find — его синоним) и find_all (select — то же самое), выражение критерия засовываем в блок:

x = [5, 8, 12, 9, 4, 30]
# find покажет нам только первый элемент, кратный шести
x.find {|e| e % 6 == 0 } # 12
# А select покажет все подходящие элементы
x.select {|e| e % 6 == 0} # [12, 30]


Метод reject обратен select — он удалит каждый элемент, удовлетворяющий блоку:

x = [5, 8, 12, 9, 4, 30]
d = c.reject {|e| e % 2 == 0} # [5, 9]


delete удалит все элементы, содержащие определенные данные:

c = ["alpha", "beta", "gamma", "delta"]
c.delete("delta")
# Теперь с = ["alpha", "beta", "gamma"]


В классе массивов определен итератор each — работает он просто, догадайтесь, что делает этот код:

[1, "test", 2, 3, 4].each { |element| puts element.to_s + "X" }

Можно создать копию массива и изменить её налету с помощью итератора collect:

[1, 2, 3, 4].collect { |element| element * 2 } #[2, 4, 6, 8]

Объединяем массивы:

x = [1, 2, 3]
y = ["a", "b", "c"]
z = x + y #[1, 2, 3, "a", "b", "c"]


a = [1, 2, 3, 4]
b = [3, 4, 5, 6]
a — b # [1, 2] — разность массивов
a & b # [3, 4] — пересечение массивов
a | b # [1, 2, 3, 4, 5, 6] — объединение с удалением дупликатов
a*2 # [1, 2, 3, 4, 1, 2, 3, 4] - повторение


Эпилог


Капля получилась относительно «жёсткая» — да, все это нужно знать :( Будем привыкать ;) Если что непонятно, то вам дорога в комментарии — там помогут. Там же ждем отзывов и замечаний!

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

Теги:
Хабы:
Всего голосов 56: ↑49 и ↓7+42
Комментарии47

Публикации

Ближайшие события