Ruby Language
Массивы
Поиск…
Синтаксис
- a = [] # с использованием литерала массива
- a = Array.new # эквивалентно использованию литерала
- a = Array.new (5) # создать массив с 5 элементами со значением nil.
- a = Array.new (5, 0) # создать массив с 5 элементами со значением по умолчанию 0.
#карта
#map
, предоставляемый Enumerable, создает массив, вызывая блок для каждого элемента и собирая результаты:
[1, 2, 3].map { |i| i * 3 }
# => [3, 6, 9]
['1', '2', '3', '4', '5'].map { |i| i.to_i }
# => [1, 2, 3, 4, 5]
Исходный массив не изменяется; возвращается новый массив, содержащий преобразованные значения в том же порядке, что и исходные значения. map!
может использоваться, если вы хотите изменить исходный массив.
В методе map
вы можете вызывать метод или использовать proc для всех элементов массива.
# call to_i method on all elements
%w(1 2 3 4 5 6 7 8 9 10).map(&:to_i)
# => [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
# using proc (lambda) on all elements
%w(1 2 3 4 5 6 7 8 9 10).map(&->(i){ i.to_i * 2})
# => [2, 4, 6, 8, 10, 12, 14, 16, 18, 20]
map
является синонимом collect
.
Создание массива с помощью конструктора literal []
Массивы могут быть созданы путем включения списка элементов в квадратных скобках ( [
и ]
). Элементы массива в этих обозначениях разделяются запятыми:
array = [1, 2, 3, 4]
Массивы могут содержать любые объекты в любой комбинации без ограничений по типу:
array = [1, 'b', nil, [3, 4]]
Создать массив строк
Массивы строк могут быть созданы с использованием синтаксиса строки ruby:
array = %w(one two three four)
Это функционально эквивалентно определению массива как:
array = ['one', 'two', 'three', 'four']
Вместо %w()
вы можете использовать другие соответствующие пары разделителей: %w{...}
, %w[...]
или %w<...>
.
Также возможно использовать произвольные не буквенно-цифровые разделители, такие как: %w!...!
, %w#...#
или %w@...@
.
%W
можно использовать вместо %w
для включения интерполяции строк. Рассмотрим следующее:
var = 'hello'
%w(#{var}) # => ["\#{var}"]
%W(#{var}) # => ["hello"]
Несколько слов можно интерпретировать, экранируя пространство с помощью \.
%w(Colorado California New\ York) # => ["Colorado", "California", "New York"]
Создать массив символов
array = %i(one two three four)
Создает массив [:one, :two, :three, :four]
.
Вместо %i(...)
вы можете использовать %i{...}
или %i[...]
или %i!...!
Кроме того, если вы хотите использовать интерполяцию, вы можете сделать это с помощью %I
a = 'hello'
b = 'goodbye'
array_one = %I(#{a} #{b} world)
array_two = %i(#{a} #{b} world)
Создает массивы: array_one = [:hello, :goodbye, :world]
array_two = [:"\#{a}", :"\#{b}", :world]
array_one = [:hello, :goodbye, :world]
и array_two = [:"\#{a}", :"\#{b}", :world]
Создать массив с массивом :: new
Пустое Array ( []
) может быть создано с помощью метода класса Array::new
, Array::new
:
Array.new
Чтобы задать длину массива, передайте числовой аргумент:
Array.new 3 #=> [nil, nil, nil]
Существует два способа заполнения массива значениями по умолчанию:
- Передайте неизменяемое значение в качестве второго аргумента.
- Передайте блок, который получает текущий индекс и генерирует изменяемые значения.
Array.new 3, :x #=> [:x, :x, :x]
Array.new(3) { |i| i.to_s } #=> ["0", "1", "2"]
a = Array.new 3, "X" # Not recommended.
a[1].replace "C" # a => ["C", "C", "C"]
b = Array.new(3) { "X" } # The recommended way.
b[1].replace "C" # b => ["X", "C", "X"]
Манипулирование элементами массива
Добавление элементов:
[1, 2, 3] << 4
# => [1, 2, 3, 4]
[1, 2, 3].push(4)
# => [1, 2, 3, 4]
[1, 2, 3].unshift(4)
# => [4, 1, 2, 3]
[1, 2, 3] << [4, 5]
# => [1, 2, 3, [4, 5]]
Удаление элементов:
array = [1, 2, 3, 4]
array.pop
# => 4
array
# => [1, 2, 3]
array = [1, 2, 3, 4]
array.shift
# => 1
array
# => [2, 3, 4]
array = [1, 2, 3, 4]
array.delete(1)
# => 1
array
# => [2, 3, 4]
array = [1,2,3,4,5,6]
array.delete_at(2) // delete from index 2
# => 3
array
# => [1,2,4,5,6]
array = [1, 2, 2, 2, 3]
array - [2]
# => [1, 3] # removed all the 2s
array - [2, 3, 4]
# => [1] # the 4 did nothing
Объединение массивов:
[1, 2, 3] + [4, 5, 6]
# => [1, 2, 3, 4, 5, 6]
[1, 2, 3].concat([4, 5, 6])
# => [1, 2, 3, 4, 5, 6]
[1, 2, 3, 4, 5, 6] - [2, 3]
# => [1, 4, 5, 6]
[1, 2, 3] | [2, 3, 4]
# => [1, 2, 3, 4]
[1, 2, 3] & [3, 4]
# => [3]
Вы также можете умножать массивы, например
[1, 2, 3] * 2
# => [1, 2, 3, 1, 2, 3]
Объединение массивов, пересечение и разность
x = [5, 5, 1, 3]
y = [5, 2, 4, 3]
Union ( |
) содержит элементы из обоих массивов с удаленными дубликатами:
x | y
=> [5, 1, 3, 2, 4]
Пересечение ( &
) содержит элементы, которые присутствуют как в первом, так и в втором массиве:
x & y
=> [5, 3]
Difference ( -
) содержит элементы, которые присутствуют в первом массиве и не присутствуют во втором массиве:
x - y
=> [1]
Фильтрация массивов
Часто мы хотим работать только с элементами массива, которые удовлетворяют конкретному условию:
Выбрать
Вернет элементы, соответствующие определенному условию
array = [1, 2, 3, 4, 5, 6]
array.select { |number| number > 3 } # => [4, 5, 6]
отклонять
Вернет элементы, которые не соответствуют определенному условию
array = [1, 2, 3, 4, 5, 6]
array.reject { |number| number > 3 } # => [1, 2, 3]
Оба #select
и #reject
возвращают массив, поэтому они могут быть скованы:
array = [1, 2, 3, 4, 5, 6]
array.select { |number| number > 3 }.reject { |number| number < 5 }
# => [5, 6]
Вставить, уменьшить
Ввод и сокращение - это разные имена для одного и того же. В других языках эти функции часто называют сгибами (например, foldl или foldr). Эти методы доступны для каждого объекта Enumerable.
Inject принимает две функции аргумента и применяет это ко всем парам элементов в массиве.
Для массива [1, 2, 3]
мы можем добавить все это вместе со стартовым значением нуля, указав начальное значение и блокируем так:
[1,2,3].reduce(0) {|a,b| a + b} # => 6
Здесь мы передаем функцию начальное значение и блок, который говорит, чтобы добавить все значения вместе. Сначала блок запускается с 0
как a
и 1
как b
а затем принимает результат этого как следующий a
поэтому мы добавляем 1
ко второму значению 2
. Затем мы берем результат этого ( 3
) и добавляем к окончательному элементу в списке ( 3
), давая нам наш результат ( 6
).
Если мы опустим первый аргумент, он установит, a
он является первым элементом в списке, поэтому приведенный выше пример совпадает с:
[1,2,3].reduce {|a,b| a + b} # => 6
Кроме того, вместо передачи блока с помощью функции мы можем передать именованную функцию как символ либо с начальным значением, либо без него. При этом приведенный выше пример можно записать в виде:
[1,2,3].reduce(0, :+) # => 6
или опуская начальное значение:
[1,2,3].reduce(:+) # => 6
Доступ к элементам
Вы можете получить доступ к элементам массива по их индексам. Нумерация индекса массива начинается с 0
.
%w(a b c)[0] # => 'a'
%w(a b c)[1] # => 'b'
Вы можете обрезать массив, используя диапазон
%w(a b c d)[1..2] # => ['b', 'c'] (indices from 1 to 2, including the 2)
%w(a b c d)[1...2] # => ['b'] (indices from 1 to 2, excluding the 2)
Это возвращает новый массив, но не влияет на оригинал. Ruby также поддерживает использование отрицательных индексов.
%w(a b c)[-1] # => 'c'
%w(a b c)[-2] # => 'b'
Вы также можете комбинировать отрицательные и положительные индексы
%w(a b c d e)[1...-1] # => ['b', 'c', 'd']
Другие полезные методы
first
используйте для доступа к первому элементу массива:
[1, 2, 3, 4].first # => 1
Или first(n)
для доступа к первым n
элементам, возвращаемым в массиве:
[1, 2, 3, 4].first(2) # => [1, 2]
Аналогично для last
и last(n)
:
[1, 2, 3, 4].last # => 4
[1, 2, 3, 4].last(2) # => [3, 4]
Используйте sample
для доступа к случайному элементу в массиве:
[1, 2, 3, 4].sample # => 3
[1, 2, 3, 4].sample # => 1
Или sample(n)
:
[1, 2, 3, 4].sample(2) # => [2, 1]
[1, 2, 3, 4].sample(2) # => [3, 4]
Двумерный массив
Используя Array::new
constructor, вы можете инициализировать массив с заданным размером и новым массивом в каждом из своих слотов. Внутренним массивам также может быть задан размер и начальное значение.
Например, для создания массива нулей 3x4:
array = Array.new(3) { Array.new(4) { 0 } }
Генерируемый массив выглядит так, когда печатается с помощью p
:
[[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]]
Вы можете читать или писать такие элементы:
x = array[0][1]
array[2][3] = 2
Массивы и оператор splat (*)
Оператор *
можно использовать для распаковки переменных и массивов, чтобы они могли передаваться как отдельные аргументы методу.
Это можно использовать для обертывания одного объекта в массиве, если его еще нет:
def wrap_in_array(value)
[*value]
end
wrap_in_array(1)
#> [1]
wrap_in_array([1, 2, 3])
#> [1, 2, 3]
wrap_in_array(nil)
#> []
В приведенном выше примере метод wrap_in_array
принимает один аргумент, value
.
Если value
является Array
, его элементы распаковываются и создается новый массив, содержащий этот элемент.
Если value
представляет собой один объект, создается новый массив, содержащий этот единственный объект.
Если value
равно nil
, возвращается пустой массив.
Оператор splat особенно удобен при использовании в качестве аргумента в методах в некоторых случаях. Например, он позволяет обрабатывать nil
, single values и массивы согласованным образом:
def list(*values)
values.each do |value|
# do something with value
puts value
end
end
list(100)
#> 100
list([100, 200])
#> 100
#> 200
list(nil)
# nothing is outputted
декомпозиция
Любой массив может быть быстро разложен путем назначения его элементов в несколько переменных. Простой пример:
arr = [1, 2, 3]
# ---
a = arr[0]
b = arr[1]
c = arr[2]
# --- or, the same
a, b, c = arr
Предшествующая переменная с оператором splat ( *
) помещает в нее массив всех элементов, которые не были захвачены другими переменными. Если ни один не оставлен, будет назначен пустой массив. В одном назначении можно использовать только один знак:
a, *b = arr # a = 1; b = [2, 3]
a, *b, c = arr # a = 1; b = [2]; c = 3
a, b, c, *d = arr # a = 1; b = 2; c = 3; d = []
a, *b, *c = arr # SyntaxError: unexpected *
Разложение безопасно и никогда не вызывает ошибок. nil
s назначаются там, где недостаточно элементов, соответствующих поведению оператора []
при доступе к индексу за пределами границ:
arr[9000] # => nil
a, b, c, d = arr # a = 1; b = 2; c = 3; d = nil
Декомпозиция пытается вызвать to_ary
неявно на назначаемый объект. Внедряя этот метод в свой тип, вы получаете возможность его разложить:
class Foo
def to_ary
[1, 2]
end
end
a, b = Foo.new # a = 1; b = 2
Если разлагаемый объект не respond_to?
to_ary
, он рассматривается как одноэлементный массив:
1.respond_to?(:to_ary) # => false
a, b = 1 # a = 1; b = nil
Разложение также можно вложить с помощью выражения ()
-delimited decposition вместо того, что в противном случае было бы единственным элементом:
arr = [1, [2, 3, 4], 5, 6]
a, (b, *c), *d = arr # a = 1; b = 2; c = [3, 4]; d = [5, 6]
# ^^^^^
Это фактически противоположно splat .
Фактически любое выражение разложения может быть ограничено ()
. Но для первого уровня декомпозиция является необязательной.
a, b = [1, 2]
(a, b) = [1, 2] # the same thing
Случай с краем: один идентификатор нельзя использовать в качестве шаблона деструкции, будь он внешним или вложенным:
(a) = [1] # SyntaxError
a, (b) = [1, [2]] # SyntaxError
При присвоении литералу массива деструктурирующему выражению внешнее []
может быть опущено:
a, b = [1, 2]
a, b = 1, 2 # exactly the same
Это называется параллельным назначением , но оно использует ту же самую разложение под капотом. Это особенно удобно для обмена значениями переменных без использования дополнительных временных переменных:
t = a; a = b; b = t # an obvious way
a, b = b, a # an idiomatic way
(a, b) = [b, a] # ...and how it works
Значения фиксируются при построении правой части задания, поэтому использование тех же переменных, что и источник и назначение, относительно безопасно.
Поверните многомерный массив в одномерный (сплющенный) массив
[1, 2, [[3, 4], [5]], 6].flatten # => [1, 2, 3, 4, 5, 6]
Если у вас многомерный массив, и вам нужно сделать его простым (то есть одномерным) массивом, вы можете использовать метод #flatten
.
Получить уникальные элементы массива
Если вам нужно прочитать элементы массива, избегающие повторений, вы используете метод #uniq
:
a = [1, 1, 2, 3, 4, 4, 5]
a.uniq
#=> [1, 2, 3, 4, 5]
Вместо этого, если вы хотите удалить все дублированные элементы из массива, вы можете использовать #uniq!
метод:
a = [1, 1, 2, 3, 4, 4, 5]
a.uniq!
#=> [1, 2, 3, 4, 5]
В то время как результат тот же, #uniq!
также сохраняет новый массив:
a = [1, 1, 2, 3, 4, 4, 5]
a.uniq
#=> [1, 2, 3, 4, 5]
a
#=> [1, 1, 2, 3, 4, 4, 5]
a = [1, 1, 2, 3, 4, 4, 5]
a.uniq!
#=> [1, 2, 3, 4, 5]
a
#=> [1, 2, 3, 4, 5]
Получить все комбинации / перестановки массива
Метод permutation
при вызове с блоком дает двумерный массив, состоящий из всех упорядоченных последовательностей набора чисел.
Если этот метод вызывается без блока, он вернет enumerator
. Чтобы преобразовать в массив, вызовите метод to_a
.
пример | Результат |
---|---|
[1,2,3].permutation | #<Enumerator: [1,2,3]:permutation |
[1,2,3].permutation.to_a | [[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]] |
[1,2,3].permutation(2).to_a | [[1,2],[1,3],[2,1],[2,3],[3,1],[3,2]] |
[1,2,3].permutation(4).to_a | [] -> Нет перестановок длины 4 |
combination
метод, с другой стороны, при вызове с блоком дает двумерный массив, состоящий из всех последовательностей набора чисел. В отличие от перестановки, порядок не учитывается в комбинациях. Например, [1,2,3]
совпадает с [3,2,1]
пример | Результат |
---|---|
[1,2,3].combination(1) | #<Enumerator: [1,2,3]:combination |
[1,2,3].combination(1).to_a | [[1],[2],[3]] |
[1,2,3].combination(3).to_a | [[1,2,3]] |
[1,2,3].combination(4).to_a | [] -> Нет комбинаций длины 4 |
Вызов метода комбинации сам по себе приведет к перечислителю. Чтобы получить массив, вызовите метод to_a
.
Методы repeated_combination
и repeated_permutation
аналогичны, за исключением того, что один и тот же элемент может повторяться несколько раз.
Например, последовательности [1,1]
, [1,3,3,1]
, [3,3,3]
недействительны в регулярных комбинациях и перестановках.
пример | # Combos |
---|---|
[1,2,3].combination(3).to_a.length | 1 |
[1,2,3].repeated_combination(3).to_a.length | 6 |
[1,2,3,4,5].combination(5).to_a.length | 1 |
[1,2,3].repeated_combination(5).to_a.length | 126 |
Создать массив последовательных чисел или букв
Это можно легко выполнить, вызвав Enumerable#to_a
в объекте Range
:
(1..10).to_a #=> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
(a..b)
означает, что он будет содержать все числа между a и b. Чтобы исключить последнее число, используйте a...b
a_range = 1...5
a_range.to_a #=> [1, 2, 3, 4]
или же
('a'..'f').to_a #=> ["a", "b", "c", "d", "e", "f"]
('a'...'f').to_a #=> ["a", "b", "c", "d", "e"]
Удобный ярлык для создания массива - [*a..b]
[*1..10] #=> [1,2,3,4,5,6,7,8,9,10]
[*'a'..'f'] #=> ["a", "b", "c", "d", "e", "f"]
Удалите все элементы nil из массива с #compact
Если массив имеет один или несколько элементов nil
их необходимо удалить, Array#compact
или Array#compact!
методы могут использоваться, как показано ниже.
array = [ 1, nil, 'hello', nil, '5', 33]
array.compact # => [ 1, 'hello', '5', 33]
#notice that the method returns a new copy of the array with nil removed,
#without affecting the original
array = [ 1, nil, 'hello', nil, '5', 33]
#If you need the original array modified, you can either reassign it
array = array.compact # => [ 1, 'hello', '5', 33]
array = [ 1, 'hello', '5', 33]
#Or you can use the much more elegant 'bang' version of the method
array = [ 1, nil, 'hello', nil, '5', 33]
array.compact # => [ 1, 'hello', '5', 33]
array = [ 1, 'hello', '5', 33]
Наконец, обратите внимание, что если #compact
или #compact!
вызывается в массиве без элементов nil
, они возвращают nil.
array = [ 'foo', 4, 'life']
array.compact # => nil
array.compact! # => nil
Создать массив чисел
Обычный способ создания массива чисел:
numbers = [1, 2, 3, 4, 5]
Объекты Range могут широко использоваться для создания массива чисел:
numbers = Array(1..10) # => [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
numbers = (1..10).to_a # => [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
#step
и #map
позволяют налагать условия на диапазон чисел:
odd_numbers = (1..10).step(2).to_a # => [1, 3, 5, 7, 9]
even_numbers = 2.step(10, 2).to_a # => [2, 4, 6, 8, 10]
squared_numbers = (1..10).map { |number| number * number } # => [1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
Все вышеперечисленные методы загружают числа с нетерпением. Если вам нужно загрузить их лениво:
number_generator = (1..100).lazy # => #<Enumerator::Lazy: 1..100>
number_generator.first(10) # => [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
Передача в массив из любого объекта
Чтобы получить массив из любого объекта, используйте Kernel#Array
.
Ниже приведен пример:
Array('something') #=> ["something"]
Array([2, 1, 5]) #=> [2, 1, 5]
Array(1) #=> [1]
Array(2..4) #=> [2, 3, 4]
Array([]) #=> []
Array(nil) #=> []
Например, вы можете заменить метод join_as_string
из следующего кода
def join_as_string(arg)
if arg.instance_of?(Array)
arg.join(',')
elsif arg.instance_of?(Range)
arg.to_a.join(',')
else
arg.to_s
end
end
join_as_string('something') #=> "something"
join_as_string([2, 1, 5]) #=> "2,1,5"
join_as_string(1) #=> "1"
join_as_string(2..4) #=> "2,3,4"
join_as_string([]) #=> ""
join_as_string(nil) #=> ""
к следующему коду.
def join_as_string(arg)
Array(arg).join(',')
end