В последнем посте мы рассказали о числах и их методах. В этом посте мы рассмотрим некоторые из коллекций Руби, такие как Arrays, Hashes и Ranges. Мы посмотрим, чем они являются, для чего они используются и что они могут сделать. Мы также узнаем, как перебирать коллекцию и как создавать циклы. В завершение мы создадим программу, которая имитирует перетасовку колоды карт, а затем превратим ее в онлайн-игру «Играй в свои карты прямо» с использованием Sinatra.
Массивы
Массив — это упорядоченный список объектов. Вы можете создать литерал массива, поместив объекты, разделенные запятыми, в квадратных скобках:
primes = [2, 3, 5, 7, 11]
Вы можете поместить любой тип объекта в массив, например строки:
 fruits = ["apples" "pears" "bananas"]
Вам даже не нужно использовать объекты одного типа:
 mixture = [1, "two", 3.0, "IV" ]
Вы даже можете иметь массив массивов, известный как многомерный массив. Это можно использовать для создания координатной системы, например так:
 coordinates = [[1,3],[4,2]]
Методы массива
Массивы являются мощным инструментом в наборе инструментов Ruby и имеют несколько очень полезных методов. Чтобы продемонстрировать некоторые из них, я буду использовать массив детей Старка:
 starks = %w(Rob Sansa Arya Bran Rickon)
=> ["Rob","Sansa","Arya","Bran","Rickon"]
Это использует немного другой синтаксис для создания массива. Если массив, который вы создаете, состоит из строк из одного слова, то вы можете использовать флаг% w в начале, чтобы указать это, а затем опустить кавычки на строках внутри массива, а также запятые, разделяющие их.
Чтобы получить доступ к определенному значению в массиве, мы записываем его положение в массиве (известное как индекс) в квадратных скобках.
 starks[1]
=> "Sansa"
  Обратите внимание, что это не первый член в массиве — это потому, что нумерация начинается с нуля.  Система нумерации также использует отрицательные значения, чтобы начать отсчет со спины, поэтому starks[-1] 
 starks[-1]
=> "Rickon"
Существуют также методы для нахождения первого и последнего элемента в массиве:
 starks[0]
=> "Rob"
starks.first
=> "Rob"
starks[-1]
=> "Rickon"
starks.last
=> "Rickon"
Мы также можем вернуть подмножество массива, указав второй параметр, который указывает длину подмассива:
 starks[2,3]
=> ["Arya","Bran","Rickon"]
В качестве альтернативы, мы можем предоставить объект Range (подробнее о диапазонах позже), который будет производить поднабор из одного индекса в другой:
 starks[2..4]
=> ["Arya","Bran","Rickon"]
  Если мы хотим узнать, сколько элементов в массиве, то мы можем использовать метод length 
 starks.length
=> 5
  Чтобы узнать, содержит ли массив объект с помощью include?  метод: 
 starks.include?("Arya")
=> true
starks.include?("Jon")
=> false
  Чтобы добавить новое значение в конец массива, используйте метод push 
 starks.push("Jon")
=> ["Rob","Sansa","Arya","Bran","Rickon","Jon"]
Для этого есть общий сокращенный оператор:
 starks << "Jon"
=> ["Rob","Sansa","Arya","Bran","Rickon","Jon"]
  Мы также можем удалить последний объект в массиве, используя метод pop 
 nightswatchman = starks.pop
=> "Jon"
Мы можем отсортировать массив в порядке (в алфавитном порядке по умолчанию для объектов String):
 starks.sort
=> ["Arya","Bran","Rickon","Rob","Sansa"]
Это фактически не изменило порядок массива, хотя:
 starks
=> ["Rob","Sansa","Arya","Bran","Rickon"]
  Для этого нам нужно использовать метод sortsort!  : 
 starks.sort!
=> ["Arya","Bran","Rickon","Rob","Sansa"]
starks
=> ["Arya","Bran","Rickon","Rob","Sansa"]
Теперь порядок массива изменился навсегда.
  reverse 
 starks.reverse
=> ["Sansa", "Rob", "Rickon", "Bran", "Arya"]
starks
=> ["Arya", "Bran", "Rickon", "Rob", "Sansa"]
starks.reverse!
=> ["Sansa", "Rob", "Rickon", "Bran", "Arya"]
starks
=> ["Sansa", "Rob", "Rickon", "Bran", "Arya"]
  Мы можем объединить все элементы массива в строку, используя метод join  Это принимает аргумент, чтобы указать, что вы хотите использовать в качестве разделителя: 
 starks.join(",")
=> "Sansa,Rob,Rickon,Bran,Arya"
Хэш
Хэши — это список пар ключ и значение. Мы можем создать хеш-литерал, поместив его в фигурные скобки
 stark = { :name => "Eddard Stark" }
Обычной практикой является использование символов для клавиш, поскольку они используют память более эффективно . Существует сокращение, которое можно использовать начиная с Ruby 1.9:
 stark = {   name: "Eddard Stark",
            lady: "Catelyn Stark",
            sigil: "Direwolf",
            motto: "Winter is Coming",
            residence: "Winterfell",
            children: ["Rob","Sansa","Arya","Bran","Rickon"]
        }
Чтобы получить доступ к значению в хэше, просто обратитесь к ключу:
 stark[:motto]
=> "Winter is Coming"
Вы можете даже иметь вложенные хэши:
 houses = { :stark => { sigil: "Direwolf", residence: "Winterfell" },
       :lannister => {sigil: "Lion", residence: "Casterly Rock" }
     }
Доступ к значениям во вложенном хэше можно получить, обратившись к каждому ключу в следующем порядке:
 houses[:lanister][:sigil]
=> "Lion"
Изменяется
  Диапазон может использоваться для представления последовательности значений.  Вы можете создать диапазон, разделив начало и конец диапазона на 2 точки (включительно) или 3 точки (исключая).  Например, 1 .. 101 ... 10 
Мы также можем создать диапазон букв:
 alphabet = "a".."z"
=> "a".."z"
К сожалению, вы не можете получить доступ к отдельным значениям Range, как вы можете с массивами и хешами:
 alphabet[2]
NoMethodError: undefined method `[]' for "a".."z":Range
  from (irb):26
  from /home/daz/.rvm/rubies/ruby-2.0.0-p247/bin/irb:16:in `<main>'
  Но есть удобный метод to_a 
 alphabet.to_a
=> ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"]
Диапазоны чаще всего используются с целыми числами и строками, но на самом деле могут использоваться с любым сопоставимым объектом (т. Е. У него есть способ определения порядка, см. Здесь для получения дополнительной информации).
Другой
  Есть и другие коллекции Ruby, одна из которых Set  Это то же самое, что и массив, но может содержать только уникальные значения.  Фактически, любой класс Ruby можно заставить работать как коллекцию, включив модуль Enumerable 
Loops
  Цикл — это структура управления, которая будет повторять блок кода, пока не будет выполнено определенное условие.  Блок кода начинается с команды doend  Вот пример цикла, использующего условие until 
 bottles = 10
until bottles == 0 do
  puts "There were #{bottles} beer bottles hanging on the wall ... "
  bottles -= 1
  puts "And if one beer bottle should accidently fall ..."
  puts "There'd be #{bottles} beer bottles hanging on the wall." 
end
  Условие здесь — количество бутылок равно нулю.  Блок кода между doend  Обратите внимание, что значение в переменной bottles  Важно, чтобы вы завершили цикл, иначе вы застрянете в бесконечном цикле. 
  Код выше может быть написан с использованием условия while 
 bottles = 10
while bottles > 0 do
  puts "There were #{bottles} beer bottles hanging on the wall ... "
  bottles -= 1
  puts "And if one beer bottle should accidently fall ..."
  puts "There'd be #{bottles} beer bottles hanging on the wall." 
end
  Время и while  Ruby предлагает их оба, чтобы вы могли написать более выразительный код, который читается больше как английский. 
итераторы
  Методы итератора позволяют нам циклически проходить по массиву, хешу или диапазону (или даже любому классу, который включает модуль until  Наиболее распространенным методом итератора является метод Enumerable  Это будет проходить через каждый объект в коллекции и затем запускать блок кода.  Например, следующий фрагмент кода выводит первые пять квадратных чисел: 
 each
  Обратите внимание, что блок принимает параметр, который находится внутри | pipe |  и приходит сразу после оператора numbers = [1,2,3,4,5]
numbers.each do |number|
  puts number * number
enddo  ,  Это представляет значение в массиве на каждой стадии цикла.  Этот цикл установит |number|number 
  Другой способ создания блока — использовать фигурные скобки для обозначения начала и финских вместо numberdo  Таким образом, приведенный выше код можно записать более кратко, как: 
 end
  Я также использовал диапазон вместо массива, просто чтобы показать, что numbers = 1 .. 5 
numbers.each { |number| puts number * number }
  Общее согласие в сообществе Ruby состоит в том, чтобы использовать блок each{ .. } 
  Выполняя итерацию по хешу, используя do .. end  Вот и пример использования абсолютного хэша из ранее: 
 each
Это дает следующий вывод:
 stark = {   
    name: "Eddard Stark",
    lady: "Catelyn Stark",
    sigil: "Direwolf",
    motto: "Winter is Coming",
    residence: "Winterfell",
    children: ["Rob","Sansa","Arya","Bran","Rickon"]
}
stark.each {|key,value| puts "#{key}: #{value}" }
  Другим полезным методом итератора является метод name: Eddard Stark
lady: Catelyn Stark
sigil: Direwolf
motto: Winter is Coming
residence: Winterfell
children: ["Rob", "Sansa", "Arya", "Bran", "Rickon"]map  Это заменяет каждое значение в массиве возвращаемым значением блока.  Таким образом, мы могли бы создать массив квадратных чисел, используя следующий код: 
 collect
  Обратите внимание, что значение numbers = [1,2,3,4,5]
=> [1, 2, 3, 4, 5]
squares = numbers.map { |number| number * number }
=> [1, 4, 9, 16, 25]numbersmap  Новый массив с именем [1,2,3,4,5]squares  Если вы хотите изменить исходный массив, используйте map  метод вместо: 
 map!
  Теперь значения в numbers = [1,2,3,4,5] 
numbers.map! { |number| number * number }
=> [1, 4, 9, 16, 25]
Создайте и перемешайте колоду карт
Теперь мы собираемся использовать некоторые из методов, которые мы изучили выше, чтобы написать программу на Ruby, которая создаст и перемешает колоду карт. Откройте ваш любимый текстовый редактор и сохраните следующее как «cards.rb»:
 numbers
  Здесь мы создаем пустой массив с именем deck = []  Затем мы создаем массив всех мастей и массив из 13 карт (от туза до короля).  Затем мы перебираем каждую масть, а затем для каждой масти, перебираем каждое значение, создавая строку для названия каждой карты (например, «Пиковый туз»), а затем помещаем эту строку в массив колод, используя сокращенный 
suits = %w[ Hearts Diamonds Clubs Spades ]
values = %w[ Ace 2 3 4 5 6 7 8 9 10 Jack Queen King ]
suits.each do |suit|
  values.each do |value|
  deck << "#{value} of #{suit}"
  end
end
deck.shuffle!
p deckdeck 
  Если вы запустите следующий код, введя  operator. 
 ruby cards.rb
Этот массив теперь можно использовать для создания всевозможных замечательных карточных игр. Говоря о которых …
Играйте в свои карты прямо в Интернете
Раньше я любил смотреть игровое шоу « Играй в свои карты», когда я был моложе, поэтому я подумал, что сделаю веб-игру, основанную на этом, используя код для колоды карт, которую мы создали выше.
Создайте файл «play your cards_right.rb» и добавьте следующий код:
 ["6 of Spades", "9 of Diamonds", "6 of Hearts", "4 of Spades", "Queen of Spades", "Queen of Hearts", "Ace of Hearts", "8 of Diamonds", "King of Hearts", "2 of Clubs", "3 of Spades", "8 of Clubs", "4 of Diamonds", "4 of Clubs", "10 of Hearts", "5 of Spades", "2 of Spades", "Queen of Clubs", "5 of Diamonds", "9 of Hearts", "10 of Spades", "6 of Diamonds", "7 of Diamonds", "9 of Spades", "7 of Hearts", "2 of Hearts", "8 of Spades", "10 of Diamonds", "7 of Clubs", "8 of Hearts", "King of Clubs", "Jack of Hearts", "5 of Clubs", "3 of Clubs", "King of Spades", "Ace of Clubs", "Ace of Diamonds", "10 of Clubs", "6 of Clubs", "Jack of Spades", "3 of Hearts", "4 of Hearts", "Jack of Clubs", "3 of Diamonds", "Queen of Diamonds", "King of Diamonds", "Ace of Spades", "7 of Spades", "5 of Hearts", "Jack of Diamonds", "9 of Clubs", "2 of Diamonds"]daz@batfink:~/Dropbox/rubysource/drafts/jones$ ruby cards.rb 
["8 of Diamonds", "5 of Clubs", "6 of Clubs", "2 of Hearts", "4 of Hearts", "8 of Hearts", "8 of Spades", "Jack of Hearts", "King of Diamonds", "Queen of Spades", "Queen of Diamonds", "9 of Spades", "6 of Diamonds", "6 of Spades", "9 of Clubs", "3 of Spades", "Ace of Spades", "9 of Hearts", "10 of Diamonds", "7 of Spades", "King of Clubs", "7 of Hearts", "5 of Spades", "7 of Clubs", "Jack of Diamonds", "3 of Hearts", "4 of Diamonds", "9 of Diamonds", "Ace of Hearts", "8 of Clubs", "2 of Diamonds", "2 of Spades", "3 of Clubs", "Queen of Hearts", "Jack of Spades", "10 of Hearts", "6 of Hearts", "Jack of Clubs", "5 of Hearts", "Ace of Diamonds", "2 of Clubs", "King of Spades", "3 of Diamonds", "4 of Clubs", "5 of Diamonds", "4 of Spades", "10 of Clubs", "Ace of Clubs", "King of Hearts", "10 of Spades", "Queen of Clubs", "7 of Diamonds"]
Это начинается с того, что требуется драгоценный камень sinatra и разрешающие сеансы (они нам понадобятся, чтобы отслеживать карты во время игры).
Далее нам понадобится обработчик маршрута, чтобы начать работу и выполнить настройку. Мы поместим это в корневой URL (‘/’):
 require 'sinatra'
enable :sessions
configure do
  set :deck, []
  suits = %w[ Hearts Diamonds Clubs Spades ]
  values = %w[ Ace 2 3 4 5 6 7 8 9 10 Jack Queen King ]
  suits.each do |suit|
    values.each do |value|
      settings.deck << "#{value} of #{suit}"
    end
  end
end
  При этом используется массив get '/' do
  session[:deck] = settings.deck.shuffle
  session[:guesses] = -1
  redirect to('/play')
endsettings.deck  Мы также установили другую переменную сеанса, чтобы отслеживать, сколько предположений сделал игрок.  После этого мы перенаправляем на маршрут configure 
Давайте настроим обработчик маршрута для этого сейчас:
 /play
  Прежде всего, вы можете подумать, что этот обработчик маршрута на самом деле не соответствует get '/:guess' do
  card = session[:deck].pop
  value = case card[0]
    when «J» then 11
    when «Q» then 12
    when «K» then 13
    else card.to_i
  end
  if (value < session[:value] and params[:guess] == ‘higher’) or (value > session[:value] and params[:guess] == ‘lower’)
    «Game Over! The card was the #{ card }. You managed to make #{session[:guesses]} correct guess#{‘es’ unless session[:guesses] == 1}. <a href=’/’>Play Again</a>»
  else
    session[:value] = value
    session[:guesses]  += 1
    «The card is the #{ card }. Do you think the next card wil be <a href=’/higher’>Higher</a> or <a href=’/lower’>Lower</a>?»
  end
end  Но это так!  Часть маршрута «: думаю» является именованным параметром .  Строка, которая идет после /play/  Он используется в игре, чтобы проверить, угадал ли игрок «выше» или «ниже».  Любое слово может быть введено в этот маршрут.  В этом случае слово «игра» использовалось как пустышка, так как игрок еще не сделал предположения. 
  Первое, что мы делаем в этом обработчике, это используем метод :guesspop  Это эквивалент раздачи карты сверху колоды. 
  Следующий фрагмент кода вычисляет числовое значение карты.  При этом используется оператор cardcase  Затем он проверяет, является ли он Джеком, Королевой или Королем, и присваивает значения 11, 12 и 13 соответственно.  Для всех остальных карт достаточно использовать метод card[0] 
  Затем следует большой оператор to_i  Во-первых, проверка, чтобы увидеть, является ли значение, хранящееся в хэше сеанса с ключом if  Затем, сравнивая это с предположением игрока, которое хранится в хэше :valueparams  Значение, сохраняемое в params[:guess]  Если игрок угадал неправильно, то отображается сообщение «Игра окончена», сообщающее игроку, что это была за карта и сколько правильных предположений они сделали. 
  Условие else относится к тому, правильно ли игрок угадывает, или, если точнее, к неверному предположению.  Это позволяет коду запускаться, если для session[:card]  Первое, что происходит, это то, что значение текущей карты сохраняется в params[:guess] 
  Запустите сервер, набрав session[:value]адресу http: // localhost: 4567 в своем браузере и ruby play_your_cards_right.rb 
Это все люди
Это подводит нас к концу этой части серии «Начало работы с Ruby». Массивы являются очень мощной частью любого инструментария программирования, и не так много программ, в которых бы не было своего рода итератора. Хеши также часто появляются во многих программах на Ruby (например, они часто используются для предоставления опций методам в Rails). Надеюсь, теперь немного понятнее, как хеши сеансов и параметров работают в Синатре.
Если вы хотите узнать еще больше о массивах, обязательно посмотрите на этот замечательный пост Роберта Куоллса, который полон еще более полезных сведений о массивах.
Теперь мы рассмотрели строки, числа и коллекции и их методы. В следующей части серии вещи начинают интересоваться, когда мы рассмотрим, как писать собственные методы.