йНМЯОЕЙР ОН МЮВЕПРЮРЕКЭМНИ ЦЕНЛЕРПХХ хМФЕМЕПМЮЪ ЦПЮТХЙЮ юПУХРЕЙРСПЮ щбл хМТНПЛЮРХЙЮ Х ХМТНПЛЮЖХНММШЕ РЕУМНКНЦХХ

Предыдущий разделУровень вышеСледующий раздел

Массивы

Ранее мы уже говорили о "простейших" объектах Ruby - числах и строках. К их числу относятся и массивы - экземпляры класса Array. Массив есть просто набор (коллекция) элементов, в котором доступ к каждому элементу возможен по его номеру (целому числу).

Массив может состоять из элементов, принадлежащих различным классам. Обратите внимание на то, что нумерация элементов массива начинается с нуля.

Чтобы создать экземпляр класса Array, его элементы, разделенные запятыми, заключают в квадратные скобки, например, [1, 2, 3].

Для задания массива строк можно использовать более удобную форму с использованием выражения %w: запись %w(раз два три) эквивалентна записи ["раз", "два", "три"]. Между символом w и открывающей скобкой не должно быть пробела. Если несколько слов должны стать одним элементом массива, то для их разделения перед пробелом добавляется символ \ (backslash):

 %w(раз\ два три\ четыре) # ["раз два", "три четыре"] 

Иногда требуется только создать массив, но не заполнять его элементами. В этом случае используется одна из следующих конструкций:

 a = [ ] b = Array.new 
Если требуется создать "пустой" массив заданного размера, то он указывается в качестве аргумента метода new, например,
 myArray = Array.new(10) # когда у функции 
только один аргумент, # скобки можно опустить myArray = Array.new 10 
Необязательный второй аргумент метода new задает класс, экземпляры которого предполагается размещать в массиве:
 timeArray = Array.new(3, Time) p timeArray #[Time, 
Time, Time] 

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

Назначение и пример использования метода    Результат   
[ ]
at
Получение элемента с указанным индексом; если аргумент является отрицательным числом, то индекс отсчитывается с конца
a = ["a", "b", "c", "d"]; a[0]; a.at(0); a[0 .. 2]
a[-2]; a.at(-2); a[2, 2]

"a"; ["a", "b", "c"]
"c"; ["c", "d"]
+ Добавление одного массива к другому
[1, 2, 3] + [4, 5]

[1, 2, 3, 4, 5]
* Повторение
[1, 2] * 2

[1, 2, 1, 2]
| Объединение множеств
["a", "b", "c"] | ["c", "d", "a"]
["a", "b", "c", "d"]
&Пересечение множеств
[1, 1, 3, 5] & [1, 2, 3]

[1, 3]
-Разность множеств
[1, 2, 2, 3, 3, 3, 4, 5] - [1, 2, 4]
[3, 5]
<<
push
Добавление в конец массива
[1, 2] << "c" << [3, 4]
a = ["a", "b"]; a.push("c", "d")
[1, 2, "c", [3, 4]]
["a", "b", "c", "d"]
unshift Добавление элемента в начало массива со сдвигом остальных
a = ["b", "c"]; a.unshift("a")


["a", "b", "c"]
clearУдаление всех элементов массива
a = ["a", "b", "c", "d"]; a.clear

[]
collectВыполнение блока операторов, заключенных в фигурные скобки, по разу для каждого элемента массива
a = ["a", "b", "c", "d"]
a.collect {|i| i+"!"}

["a!", "b!", "c!", "d!"]
compact Удаление всех объектов nil из массива
["a", "b", nil, "c", nil].compact
["a", "b", "c"]
empty? Проверка на отсутствие элементов массива
[].empty?
true
length
size
Определение количества элементов массива
[ 1, 2, 3, 4, 5 ].length
5
pop Удаление последнего элемента массива
a = [ "a", "m", "z" ]; a.pop
a


"z"
["a", "m"]
each Вызов блока операторов по одному разу для каждого элемента массива
a = ["a", "b", "c"]
a.each {|x| print x, "--" }

a--b--c--
flatten "Разглаживание" массива - получение одномерного массива из массива массивов
s = [ 1, 2, 3 ]
t = [ 4, 5, 6, [7, 8] ]
a = [ s, t, 9, 10 ]; a.flatten




[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
index Получение номера первого вхождения аргумента (nil если не найден)
a = [ "a", "b", "c" ]; a.index("b")
a.index("z")

 
 
1
nil
join Создание единой строки из массива строк
[ "a", "b", "c" ].join
[ "a", "b", "c" ].join("-")

"abc"
"a-b-c"
nitems Определение количества элементов массива, отличных от nil
[ 1, nil, 3, nil, 5 ].nitems
3
reverse Инвертирование массива
[ "a", "b", "c" ].reverse
[ 1 ].reverse
["c", "b", "a"]
[1]
sort Сортировка массива
a = ["d", "a", "c"]
a.sort
a.sort {|x,y| y <=> x }

["a", "c", "d"]

["d", "c", "a"]

Будьте внимательны при сортировке строк, содержащих буквы русского алфавита. Упорядочивание строк происходит по ASCII-кодам их символов, а таблица кодировки koi8-r, принятая в ОС Linux, размещает русские буквы не в алфавитном порядке.

 a2 = %w(собака 
волк лошадь альбатрос) puts a2.sort # альбатрос лошадь собака волк 


Пример
Создайте файл, в который поместите следующую программу.

 a = [1, "cat", 3.14] 
# создание массива из трех элементов puts a puts a[0] # печать первого элемента 
массива puts a.type print a[0].type, "\t", a[1].type, "\t", a[2].type, "\n" a[2] 
= "dog" # изменение значения третьего элемента puts a print a[0].type, "\t", a[1].type, 
"\t", a[2].type, "\n" 

(Загрузить файл с примером)

Проследите за изменениями типа элементов массива a.

Будьте внимательны при присваивании значений переменным, если они есть ссылки на массивы. Рассмотрим следующий пример, комментируя действия с переменными в терминах "наклеек":

 # "упаковываем" массив Ruby puts "\n\t Массивы " magic 
= [1, 2] # обе метки наклеены на одну и ту же упаковку hocusPocus = magic # их 
значения совпадают print "magic = "; p magic print "hocusPocus = "; p hocusPocus 
puts "изменяем содержимое массива hocusPocus" # изменим содержимое упаковки с 
именем hocusPocus hocusPocus[0] = 6 print "magic = "; p magic # посмотрим... print 
"hocusPocus = "; p hocusPocus puts "Обе переменные изменились" 

(Загрузить файл с примером)

Так же, как массивы, ведут себя в языке Ruby почти все объекты. Исключением являются числа (Fixnum), логические величины true и false, а также специальная величина nil (ноль, ничего), используемая для ссылки "в никуда". Когда вы присваиваете значение переменной, указывающей на объект одного из вышеперечисленных типов, другой переменной, эти две переменные начинают ссылаться на два различных объекта, имеющих одинаковое значение, а не на один и тот же объект. Например,

 puts"===============" 
puts "\n \t Числа " # "упаковали" объект типа FixNum magic = 42 # теперь имеем 
две упаковки, каждая со своей меткой hocusPocus = magic # обе упаковки имеют одинаковое 
содержимое puts "magic = #{magic}" puts "hocusPocus = #{hocusPocus}" puts "изменяем 
содержимое hocusPocus" # изменим содержимое упаковки с именем hocusPocus hocusPocus 
= 0 # посмотрим... puts "magic = #{magic}" # и заметим, что они различны puts 
"hocusPocus = #{hocusPocus}" puts "Вторая переменная не изменилась" 

Значения, присваиваемые переменным, могут являться выражениями или массивами. Если число элементов в правой части больше числа переменных в левой, то лишние значения игнорируются. Если число переменных слева превышает число значений справа, то оставшиеся переменные принимают значение nil. Символ * перед именем последней переменной в списке указывает, что она является массивом, в который помещаются оставшиеся значения.

 a, b = [1, 2] # a = 1; b = 2 a, 
b = 1, 2 # a = 1; b = 2 a, b, c = 1, 2 # a = 1; b = 2; c = nil a, b = 1, 2, 3 
# a = 1; b = 2 a, *b = 1, 2, 3 # a = 1; b = [2, 3] 

В Ruby, как и в большинстве других современных языков, нет многомерных массивов, но они легко моделируются созданием массива массивов, т. е. массива, элементами которого являются также массивы. Как следствие, такие массивы не обязаны быть прямоугольными (т. е. число элементов в разных строках может отличаться), что позволяет значительно экономить память. Например, двумерный массив размером 3x3 можно задать так

 
a = [ [11, 12, 13], [21, 22, 23], [31, 32, 33] ] 
Аналогично можно создать массив любой требуемой размерности, хотя массивы размерности, большей чем два, встречаются достаточно редко. К элементам таких массивов можно добраться, последовательно указывая индексы требуемых элементов:
 p a[1] # [21, 22, 23], p a[1][1] # 
22 

Если требуется только создать многомерный массив, не заполняя его данными, то следует использовать следующую конструкцию:

 # Пустой массив: 
# создали три разных массива и поместили их в четвертый a = Array.new(3) a[0] 
= Array.new(3) a[1] = Array.new(3) a[2] = Array.new(3) a[1][1] = 123 p a # [[nil, 
nil, nil], [nil, 123, nil], [nil, nil, nil]] 
Метод map, который выполняет блок операторов, следующий за ним, для каждого элемента объекта, к которому он применяется, позволяет более компактно реализовать рассмотренную выше конструкцию:
 a = (0..2).map{ Array.new(3)} # ПРАВИЛЬНО a[1][1] = 123 p a # [[nil, nil, 
nil], [nil, 123, nil], [nil, nil, nil]] 
Попытка же создать такой массив, аналогично одномерному, приводит к неожиданным на первый взгляд результатам:
 
b = Array.new(3, Array.new(3)) # НЕПРАВИЛЬНО # создали массив, в который поместили 
# три ссылки на один и тот же объект b[1][1] = 123 p b # [[nil, 123, nil], [nil, 
123, nil], [nil, 123, nil]] 


Пример
Рассмотрим создание массива размера 3x3, который должен быть заполнен по следующей схеме: в первой строке массива - текущие год, номер месяца и дня месяца, во второй - название месяца, день и наименование дня недели, в третьей строке - текущие час, минута и секунда.

 myArray = (0..2).map{ Array.new 3 } mouth = %w(январь февраль 
март апрель май июнь июль август сентябрь октябрь ноябрь декабрь) dayOfWeek = 
%w(воскресенье понедельник вторник среда четверг пятница суббота) t = Time.now 
myArray[0][0] = t.year myArray[0][1] = t.month myArray[0][2] = t.day myArray[1][0] 
= mouth[t.month] myArray[1][1] = t.day myArray[1][2] = dayOfWeek[t.wday] myArray[2][0] 
= t.hour myArray[2][1] = t.min myArray[2][2] = t.sec print "Сегодня #{myArray[0][2]}.", 
"#{myArray[0][1]}.#{myArray[0][0]}\n" print "Число: #{myArray[1][1]}, ", "месяц: 
#{myArray[1][0]},", " день недели: #{myArray[1][2]}\n" print "Сейчас #{myArray[2][0]} 
час, ", "#{myArray[2][1]} мин,", " #{myArray[2][2]}сек\n" 

(Загрузить файл с примером)


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

 b = [23, -14, 45, 78, -2.5] s = 0 b.each {|i| s 
+=i} puts s 

(Загрузить файл с примером)

Задания
  1. Напишите программу, печатающую среднее арифметическое первого и последнего элементов массива.
  2. Напишите программу, находящую пересечение и объединение двух множеств A={1,2,3} и B={2,4,5}, используя методы работы с массивами.

Предыдущий разделУровень вышеСледующий раздел

мЮВЕПРЮРЕКЭМЮЪ ЦЕНЛЕРПХЪ Х ХМФЕМЕПМЮЪ ЦПЮТХЙЮ, ОЕПЯОЕЙРХБЮ