В последнем посте мы рассказали о числах и их методах. В этом посте мы рассмотрим некоторые из коллекций Руби, такие как 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"]
Для этого нам нужно использовать метод sort
sort!
:
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 .. 10
1 ... 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
Цикл — это структура управления, которая будет повторять блок кода, пока не будет выполнено определенное условие. Блок кода начинается с команды do
end
Вот пример цикла, использующего условие 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
Условие здесь — количество бутылок равно нулю. Блок кода между do
end
Обратите внимание, что значение в переменной 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
Другой способ создания блока — использовать фигурные скобки для обозначения начала и финских вместо number
do
Таким образом, приведенный выше код можно записать более кратко, как:
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]numbers
map
Новый массив с именем [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
/
Он используется в игре, чтобы проверить, угадал ли игрок «выше» или «ниже». Любое слово может быть введено в этот маршрут. В этом случае слово «игра» использовалось как пустышка, так как игрок еще не сделал предположения.
Первое, что мы делаем в этом обработчике, это используем метод :guess
pop
Это эквивалент раздачи карты сверху колоды.
Следующий фрагмент кода вычисляет числовое значение карты. При этом используется оператор card
case
Затем он проверяет, является ли он Джеком, Королевой или Королем, и присваивает значения 11, 12 и 13 соответственно. Для всех остальных карт достаточно использовать метод card[0]
Затем следует большой оператор to_i
Во-первых, проверка, чтобы увидеть, является ли значение, хранящееся в хэше сеанса с ключом if
Затем, сравнивая это с предположением игрока, которое хранится в хэше :value
params
Значение, сохраняемое в params[:guess]
Если игрок угадал неправильно, то отображается сообщение «Игра окончена», сообщающее игроку, что это была за карта и сколько правильных предположений они сделали.
Условие else относится к тому, правильно ли игрок угадывает, или, если точнее, к неверному предположению. Это позволяет коду запускаться, если для session[:card]
Первое, что происходит, это то, что значение текущей карты сохраняется в params[:guess]
Запустите сервер, набрав session[:value]
адресу http: // localhost: 4567 в своем браузере и ruby play_your_cards_right.rb
Это все люди
Это подводит нас к концу этой части серии «Начало работы с Ruby». Массивы являются очень мощной частью любого инструментария программирования, и не так много программ, в которых бы не было своего рода итератора. Хеши также часто появляются во многих программах на Ruby (например, они часто используются для предоставления опций методам в Rails). Надеюсь, теперь немного понятнее, как хеши сеансов и параметров работают в Синатре.
Если вы хотите узнать еще больше о массивах, обязательно посмотрите на этот замечательный пост Роберта Куоллса, который полон еще более полезных сведений о массивах.
Теперь мы рассмотрели строки, числа и коллекции и их методы. В следующей части серии вещи начинают интересоваться, когда мы рассмотрим, как писать собственные методы.