Категории
Самые читаемые
Лучшие книги » Компьютеры и Интернет » Программирование » Программирование на языке Ruby - Хэл Фултон

Программирование на языке Ruby - Хэл Фултон

Читать онлайн Программирование на языке Ruby - Хэл Фултон

Шрифт:

-
+

Интервал:

-
+

Закладка:

Сделать
1 ... 54 55 56 57 58 59 60 61 62 ... 156
Перейти на страницу:

x = [1, 2, 3]

x.clear

# x равно []

8.1.16. Конкатенирование массивов и добавление в конец массива

Часто нужно добавить в конец существующего массива отдельный элемент или целый массив. В Ruby это можно сделать разными способами.

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

x = [1, 5, 9]

x << 13       # x равно [1, 5, 9, 13]

x << 17 << 21 # x равно [1, 5, 9, 13, 17, 21].

Аналогичную операцию выполняют методы unshift и push, которые добавляют элемент в начало и в конец массива соответственно (см. также следующий раздел данной главы).

Массивы можно конкатенировать методом concat или с помощью операторов + и +=:

x = [1,2]

y = [3,4]

z = [5,6]

b = y + z  # [3,4,5,6]

b += x     # [3,4,5,6,1,2]

z.concat у # z равно [5,6,3,4]

Имейте в виду, что оператор += всегда создает новый объект. Также не забывайте, что оператор << добавляет в конец новый элемент, который сам может быть массивом.

a = [1,2]

b = [3,4]

a += b          # [1,2,3,4]

a = [1,2]

b = [3,4]

а << b          # [1,2, [3,4]]

a = [1,2]

b = [3,4]

а = a.concat(b) # [1,2,3,4]

8.1.17. Использование массива в качестве стека или очереди

Базовые операции со стеком называются push и pop, они добавляют и удаляют элементы в конец массива. Базовые операции с очередью — это shift (удаляет элемент из начала массива) и unshift (добавляет элемент в начало массива). Для добавления в конец массива можно также пользоваться оператором << (по существу синоним push).

Постарайтесь не запутаться. Методы shift и unshift модифицируют массив в начале, a push, pop и << — в конце.

Эта тема будет продолжена в разделе 9.2.

8.1.18. Обход массива

Как и следовало ожидать, в классе Array есть стандартный итератор each. Но имеются и другие полезные итераторы.

Метод reverse_each обходит массив в обратном порядке. Результат такой же, как если бы мы вызвали сначала метод reverse, а потом each, но работает быстрее.

words = %w(Son I am able she said)

str = ""

words.reverse_each { |W| str += "#{w} "}

# str равно "said she able am I Son "

Если нужно только перебрать все индексы, можно воспользоваться итератором each_index. Конструкция x.each_index эквивалентна (0..(x.size-1)).each (то есть обходу всего диапазона индексов).

Итератор each_with_index (подмешанный из модуля Comparable) передает в блок как сам элемент, так и его индекс.

x = ["alpha", "beta", "gamma"]

x.each_with_index do |x,i|

 puts "Элемент #{i} равен #{x}"

end

# Выводятся три строки.

Предположим, что нужно обойти массив в случайном порядке. Ниже представлен итератор random_each (который просто вызывает метод randomize, описанный в разделе 8.1.10).

class Array

 # Предполагается, что метод randomize определен.

 def random_each

  temp = self.randomize

  temp.each {|x| yield x}

 end

end

dwarves = %w(Sleepy Dopey Happy Sneezy Grumpy Bashful Doc)

list = ""

dwarves.random_each (|x| list += "#{x} "}

# list равен:

# "Bashful Dopey Sleepy Happy Grumpy Doc Sneezy "

# (Ha вашей машине порядок может быть другим.)

8.1.19. Преобразование массива в строку с разделителями

Часто требуется вставить разделители между элементами массива, но не перед первым и не после последнего. Для этого предназначены метод join и оператор *.

been_there = ["Veni", "vidi", "vici."]

journal = been_there.join(", ") # "Veni, vidi, vici."

letters = ["Phi","Mu","Alpha"]

musicians = letters.join(" ")   # "Phi Mu Alpha"

people = ["Bob","Carol","Ted","Alice"] movie = people * " and "

# movie равно "Bob and Carol and Ted and Alice"

Если необходимо обрабатывать последний элемент особым образом, например вставить перед ним слово «and», это можно сделать вручную:

list = %w[A В С D Е F]

with_commas = list[0..-2]*", " + ", and " + list[-1]

# with_commas равно "А, В, C, D, E, and F"

8.1.20. Обращение массива

Чтобы переставить элементы массива в обратном порядке, воспользуйтесь методами reverse или reverse!:

inputs = ["red", "green", "blue"]

outputs = inputs.reverse # ["green","blue","red"]

priorities = %w(eat sleep code)

priorities.reverse! # ["code","sleep","eat"]

8.1.21. Удаление дубликатов из массива

Чтобы удалить из массива повторяющиеся экземпляры, воспользуйтесь методом uniq (или его вариантом для модификации на месте uniq!):

breakfast = %w[spam spam eggs ham eggs spam]

lunch = breakfast.uniq # ["spam","eggs","ham"]

breakfast.uniq! # Массив breakfast изменился.

8.1.22. Чередование массивов

Предположим, что есть два массива и надо построить из них третий, который содержит массивы из двух элементов, взятых из соответственных позиций исходных массивов. В последних версиях Ruby модуль Enumerable содержит метод zip:

a = [1, 2, 3, 4]

b = ["a", "b", "c", "d"]

с = a.zip(b)

# с равно [[1,"а" ] , [2,"b"], [3,"с"], [4,"d"]]

# Чтобы устранить вложенность, воспользуйтесь методом flatten

d = с.flatten

# d равно [1, "а", 2, "b", 3, "с", 4, "d"]

8.1.23. Вычисление частоты различных значений в массиве

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

class Array

 def count

  k=Hash.new(0)

  self.each{|x| k[x]+=1 }

  k

 end

end

meal = %w[spam spam eggs ham eggs spam]

items = meal.count

# items равно {"ham" => 1, "spam" => 3, "eggs" => 2}

spams = items["spam"] # 3

Обратите внимание, что метод возвращает хэш.

8.1.24. Инвертирование массива для получения хэша

Массив нужен для того, чтобы ассоциировать целое число (индекс) с данными. А если нужно инвертировать это отношение, то есть ассоциировать данные с индексом? Иными словами, породить хэш? Это можно сделать так:

class Array

 def invert

  h={}

  self.each_with_index{|x,i| h[x]=i}

  h

 end

end

a = ["red","yellow","orange"]

h = a.invert # {"orange"=>2, "yellow"=>1, "red"=>0}

8.1.25. Синхронная сортировка нескольких массивов

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

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

class Array

 def sort_index

  d=[]

  self.each_with_index{|x, i| d[i]=[x,i]}

  if block_given?

   d.sort {|x,у| yield x[0],y[0]}.collect{|x| x[1]}

  else

   d.sort.collect{|x| x[1]}

  end

 end

 def sort_with(ord=[])

  return nil if self.length!=ord.length

  self.values_at(*ord)

 end

end

a = [21, 33, 11, 34, 36, 24, 14]

b = a.sort_index

a2 = a.sort_with(b)

c = a.sort_index {|x,y| x%2 <=> y%2 }

a3 = a.sort_with(c)

p a  # [21, 33, 11, 34, 36, 24, 14]

p b  # [2,6,0,5,1,3,4]

p a2 # [11, 14, 21, 24, 33, 34, 36]

p c  # [6, 5, 4, 3, 2, 1, 0]

p a3 # [14, 24, 36, 34, 11, 33, 21]

8.1.26. Указание значения по умолчанию для новых элементов массива

Когда массив растет и в нем создаются новые элементы, по умолчанию им присваивается значение nil:

a = Array.new

a[0]="x"

a[3]="y"

# а равно ["x", nil, nil, "y"]

Но, допустим, нам требуется, чтобы новые элементы получали другое значение. Тогда в качестве конкретного применения общего принципа предлагаем класс ZArray, описывающий массив, в котором вновь созданные элементы будут равны 0:

class ZArray < Array

 def [](x)

  if x > size

   for i in size+1..x

    self[i]=0

1 ... 54 55 56 57 58 59 60 61 62 ... 156
Перейти на страницу:
На этой странице вы можете бесплатно скачать Программирование на языке Ruby - Хэл Фултон торрент бесплатно.
Комментарии