класс Array
Объект Array — это упорядоченная коллекция объектов с целочисленной индексацией, называемых элементами; объект представляет собой структуру данных «массив».
Элементом может быть любой объект (даже другой массив); в массиве могут сочетаться объекты разных типов.
К важным структурам данных, использующим массивы, относятся:
Существуют также структуры данных, похожие на массивы:
-
Ассоциативный массив (см.
Hash). -
Множество (см. Set).
Индексы массива
Индексация массива начинается с 0, как в C или Java.
Неотрицательный индекс задаёт смещение от первого элемента:
-
Индекс 0 указывает на первый элемент.
-
Индекс 1 указывает на второй элемент.
-
…
Отрицательный индекс задаёт смещение от конца массива в обратном направлении:
-
Индекс -1 указывает на последний элемент.
-
Индекс -2 указывает на предпоследний элемент.
-
…
Индексы в диапазоне и вне диапазона
Неотрицательный индекс находится в диапазоне тогда и только тогда, когда он меньше размера массива. Для массива из 3 элементов:
-
Индексы от 0 до 2 входят в диапазон.
-
Индекс 3 находится вне диапазона.
Отрицательный индекс находится в диапазоне тогда и только тогда, когда его абсолютное значение не превышает размер массива. Для массива из 3 элементов:
-
Индексы от -1 до -3 входят в диапазон.
-
Индекс -4 находится вне диапазона.
Эффективный индекс
Хотя эффективный индекс в массиве всегда является целым числом, некоторые методы (как в классе Array, так и в других местах) принимают один или несколько нецелочисленных аргументов — объектов, преобразуемых в целое число.
Создание массивов
Создать объект Array явно можно с помощью:
-
[1, 'one', :one, [2, 'two', :two]]
-
Литерала строкового массива %w или %W:
%w[foo bar baz] # => ["foo", "bar", "baz"] %w[1 % *] # => ["1", "%", "*"]
-
Литерала массива символов %i или %I:
%i[foo bar baz] # => [:foo, :bar, :baz] %i[1 % *] # => [:"1", :%, :*]
-
Метода
Kernel#Array:Array(["a", "b"]) # => ["a", "b"] Array(1..5) # => [1, 2, 3, 4, 5] Array(key: :value) # => [[:key, :value]] Array(nil) # => [] Array(1) # => [1] Array({:a => "a", :b => "b"}) # => [[:a, "a"], [:b, "b"]] -
Метода
Array.new:Array.new # => [] Array.new(3) # => [nil, nil, nil] Array.new(4) {Hash.new} # => [{}, {}, {}, {}] Array.new(3, true) # => [true, true, true]Обратите внимание, что в последнем примере выше массив заполняется ссылками на один и тот же объект. Такой подход рекомендуется только в случаях, когда этот объект изначально неизменяем, например, символ, числовое значение,
nil,trueилиfalse.Другой способ создать массив с различными объектами — использовать блок; этот вариант безопасен для изменяемых объектов, таких как хеши, строки или другие массивы:
Array.new(4) {|i| i.to_s } # => ["0", "1", "2", "3"]Вот способ создать многомерный массив:
Array.new(3) {Array.new(3)} # => [[nil, nil, nil], [nil, nil, nil], [nil, nil, nil]]
Ряд методов Ruby, как в ядре, так и в стандартной библиотеке, предоставляет метод экземпляра to_a, который преобразует объект в массив.
-
Benchmark::Tms#to_a
-
CSV::Table#to_a
-
Gem::List#to_a
-
Gem::NameTuple#to_a -
Gem::Platform#to_a -
Gem::RequestSet::Lockfile::Tokenizer#to_a -
Gem::SourceList#to_a -
Racc::ISet#to_a
-
Rinda::RingFinger#to_a
-
Ripper::Lexer::Elem#to_a
Пример использования
Помимо методов, включённых через модуль Enumerable, класс Array имеет собственные методы для доступа к массивам, поиска в них и других манипуляций с ними.
Ниже приведены примеры некоторых наиболее распространённых методов.
Доступ к элементам
Получить элементы массива можно с помощью метода Array#[]. Он принимает один целочисленный аргумент (числовой индекс), пару аргументов (начало и длину) или диапазон. Отрицательные индексы отсчитываются от конца, где -1 соответствует последнему элементу.
arr = [1, 2, 3, 4, 5, 6] arr[2] #=> 3 arr[100] #=> nil arr[-3] #=> 4 arr[2, 3] #=> [3, 4, 5] arr[1..4] #=> [2, 3, 4, 5] arr[1..-3] #=> [2, 3, 4]
Ещё один способ получить определённый элемент массива — использовать метод at.
arr.at(0) #=> 1
Метод slice работает так же, как Array#[].
Чтобы вызвать ошибку при выходе индексов за границы массива или задать значение по умолчанию на такой случай, можно использовать fetch.
arr = ['a', 'b', 'c', 'd', 'e', 'f'] arr.fetch(100) #=> IndexError: index 100 outside of array bounds: -6...6 arr.fetch(100, "oops") #=> "oops"
Специальные методы first и last возвращают соответственно первый и последний элементы массива.
arr.first #=> 1 arr.last #=> 6
Чтобы вернуть первые n элементов массива, используйте take.
arr.take(3) #=> [1, 2, 3]
drop делает противоположное take: возвращает элементы после пропуска n элементов:
arr.drop(3) #=> [4, 5, 6]
Получение информации о массиве
Массив постоянно отслеживает свою длину. Чтобы узнать количество содержащихся в нём элементов, используйте length, count или size.
browsers = ['Chrome', 'Firefox', 'Safari', 'Opera', 'IE'] browsers.length #=> 5 browsers.count #=> 5
Чтобы проверить, содержит ли массив хотя бы один элемент:
browsers.empty? #=> false
Чтобы проверить, содержится ли в массиве определённый элемент:
browsers.include?('Konqueror') #=> false
Добавление элементов в массив
Добавить элементы в конец массива можно с помощью push или <<.
arr = [1, 2, 3, 4] arr.push(5) #=> [1, 2, 3, 4, 5] arr << 6 #=> [1, 2, 3, 4, 5, 6]
unshift добавляет новый элемент в начало массива.
arr.unshift(0) #=> [0, 1, 2, 3, 4, 5, 6]
С помощью insert можно добавить новый элемент в любую позицию массива.
arr.insert(3, 'apple') #=> [0, 1, 2, 'apple', 3, 4, 5, 6]
Метод insert также позволяет вставить сразу несколько значений:
arr.insert(3, 'orange', 'pear', 'grapefruit') #=> [0, 1, 2, "orange", "pear", "grapefruit", "apple", 3, 4, 5, 6]
Удаление элементов из массива
Метод pop удаляет последний элемент массива и возвращает его:
arr = [1, 2, 3, 4, 5, 6] arr.pop #=> 6 arr #=> [1, 2, 3, 4, 5]
Чтобы получить и одновременно удалить первый элемент, используйте shift:
arr.shift #=> 1 arr #=> [2, 3, 4, 5]
Чтобы удалить элемент по определённому индексу:
arr.delete_at(2) #=> 4 arr #=> [2, 3, 5]
Чтобы удалить определённый элемент из массива, используйте delete:
arr = [1, 2, 2, 3] arr.delete(2) #=> 2 arr #=> [1,3]
Если нужно удалить из массива значения nil, пригодится метод compact:
arr = ['foo', 0, nil, 'bar', 7, 'baz', nil] arr.compact #=> ['foo', 0, 'bar', 7, 'baz'] arr #=> ['foo', 0, nil, 'bar', 7, 'baz', nil] arr.compact! #=> ['foo', 0, 'bar', 7, 'baz'] arr #=> ['foo', 0, 'bar', 7, 'baz']
Ещё одна распространённая задача — удаление повторяющихся элементов из массива.
Для этого есть неразрушающий метод uniq и разрушающий метод uniq!.
arr = [2, 5, 6, 556, 6, 6, 8, 9, 0, 123, 556] arr.uniq #=> [2, 5, 6, 556, 8, 9, 0, 123]
Перебор массива
Как и все классы, подключающие модуль Enumerable, класс Array имеет метод each, который определяет, какие элементы перебирать и как это делать. В случае Array#each все элементы self последовательно передаются указанному блоку.
Обратите внимание, что эта операция не изменяет массив.
arr = [1, 2, 3, 4, 5]
arr.each {|a| print a -= 10, " "}
# prints: -9 -8 -7 -6 -5
#=> [1, 2, 3, 4, 5]
Ещё один иногда полезный итератор — reverse_each, который перебирает элементы массива в обратном порядке.
words = %w[first second third fourth fifth sixth]
str = ""
words.reverse_each {|word| str += "#{word} "}
p str #=> "sixth fifth fourth third second first "
Метод map можно использовать для создания нового массива на основе исходного, изменив значения с помощью заданного блока:
arr.map {|a| 2*a} #=> [2, 4, 6, 8, 10]
arr #=> [1, 2, 3, 4, 5]
arr.map! {|a| a**2} #=> [1, 4, 9, 16, 25]
arr #=> [1, 4, 9, 16, 25]
Выбор элементов из массива
Элементы массива можно выбирать по критериям, заданным в блоке. Выбор может выполняться разрушающим или неразрушающим способом. Разрушающие операции изменяют массив, к которому применяются; неразрушающие методы обычно возвращают новый массив с выбранными элементами, оставляя исходный массив без изменений.
Неразрушающий выбор
arr = [1, 2, 3, 4, 5, 6]
arr.select {|a| a > 3} #=> [4, 5, 6]
arr.reject {|a| a < 3} #=> [3, 4, 5, 6]
arr.drop_while {|a| a < 4} #=> [4, 5, 6]
arr #=> [1, 2, 3, 4, 5, 6]
Разрушающий выбор
select! и reject! — соответствующие разрушающие методы для select и reject.
Подобно тому, как select и reject дают противоположные результаты, методы delete_if и keep_if при передаче одного и того же блока дают прямо противоположные результаты:
arr.delete_if {|a| a < 4} #=> [4, 5, 6]
arr #=> [4, 5, 6]
arr = [1, 2, 3, 4, 5, 6]
arr.keep_if {|a| a < 4} #=> [1, 2, 3]
arr #=> [1, 2, 3]
Что здесь есть
Сначала — о том, что находится в других местах. Класс Array:
-
Наследуется от класса Object.
-
Подключает модуль Enumerable, который предоставляет десятки дополнительных методов.
Здесь класс Array предоставляет методы, предназначенные для:
Методы для создания массива
-
::[]: возвращает новый массив, заполненный заданными объектами. -
::new: возвращает новый массив. -
::try_convert: возвращает новый массив, созданный на основе заданного объекта.
См. также раздел Создание массивов.
Методы для проверки
-
all?: возвращает, удовлетворяют ли все элементы заданному критерию. -
any?: возвращает, удовлетворяет ли хотя бы один элемент заданному критерию. -
count: возвращает количество элементов, удовлетворяющих заданному критерию. -
empty?: возвращает, пуст ли массив. -
find_index(псевдонимindex): возвращает индекс первого элемента, удовлетворяющего заданному критерию. -
hash: возвращает целочисленный хеш-код. -
include?: возвращает,==ли какой-либо элемент заданному объекту. -
none?: возвращает,==ли ни один элемент заданному объекту. -
one?: возвращает,==ли ровно один элемент заданному объекту. -
rindex: возвращает индекс последнего элемента, удовлетворяющего заданному критерию.
Методы для сравнения
-
<=>: возвращает -1, 0 или 1 в зависимости от того, меньше лиselfзаданного объекта, равен ему или больше него. -
==: возвращает,selfли каждый элемент==соответствующему элементу заданного объекта. -
eql?: возвращает,selfли каждый элементeql?соответствующему элементу заданного объекта.
Методы для получения элементов
Эти методы не изменяют self.
-
[](псевдонимslice): возвращает последовательность элементов, определяемую заданным аргументом. -
assoc: возвращает первый элемент, который является массивом, первый элемент которого==заданному объекту. -
at: возвращает элемент по заданному смещению. -
bsearch: возвращает элемент, выбранный с помощью двоичного поиска согласно заданному блоку. -
bsearch_index: возвращает индекс элемента, выбранного с помощью двоичного поиска согласно заданному блоку. -
compact: возвращает массив, содержащий все элементы, кромеnil. -
dig: возвращает объект во вложенных объектах, указанный заданным индексом и дополнительными аргументами. -
drop: возвращает конечные элементы, определяемые заданным индексом. -
drop_while: возвращает конечные элементы, определяемые заданным блоком. -
fetch: возвращает элемент по заданному смещению. -
fetch_values: возвращает элементы по заданным смещениям. -
first: возвращает один или несколько начальных элементов. -
last: возвращает один или несколько конечных элементов. -
max: возвращает один или несколько элементов с максимальными значениями, определяемыми методом<=>или заданным блоком. -
min: возвращает один или несколько элементов с минимальными значениями, определяемыми методом<=>или заданным блоком. -
minmax: возвращает элементы с минимальным и максимальным значениями, определяемыми методом<=>или заданным блоком. -
rassoc: возвращает первый элемент, который является массивом, второй элемент которого==заданному объекту. -
reject: возвращает массив с элементами, не отклонёнными заданным блоком. -
reverse: возвращает все элементы в обратном порядке. -
rotate: возвращает все элементы, переместив некоторые из одного конца в другой. -
sample: возвращает один или несколько случайных элементов. -
select(псевдонимfilter): возвращает массив с элементами, выбранными заданным блоком. -
shuffle: возвращает элементы в случайном порядке. -
sort: возвращает все элементы в порядке, определяемом методом<=>или заданным блоком. -
take: возвращает начальные элементы, определяемые заданным индексом. -
take_while: возвращает начальные элементы, определяемые заданным блоком. -
uniq: возвращает массив, содержащий элементы без дубликатов. -
values_at: возвращает элементы по заданным смещениям.
Методы для присваивания
Эти методы добавляют, заменяют или переупорядочивают элементы в self.
-
<<: добавляет элемент в конец. -
[]=: присваивает указанным элементам заданный объект. -
concat: добавляет все элементы из заданных массивов. -
fill: заменяет указанные элементы заданными объектами. -
flatten!: заменяет каждый вложенный массив вselfего элементами. -
initialize_copy(псевдонимreplace): заменяет содержимоеselfсодержимым заданного массива. -
insert: вставляет заданные объекты по указанному смещению, не заменяя элементы. -
reverse!: заменяетselfмассивом с элементами в обратном порядке. -
rotate!: заменяетselfмассивом с циклически сдвинутыми элементами. -
shuffle!: заменяетselfмассивом с элементами в случайном порядке. -
sort!: заменяетselfмассивом с отсортированными элементами в порядке, определяемом методом<=>или заданным блоком. -
sort_by!: заменяетselfмассивом с элементами, отсортированными согласно заданному блоку.
Методы для удаления
Каждый из этих методов удаляет элементы из self:
-
clear: удаляет все элементы. -
compact!: удаляет все элементыnil. -
delete: удаляет элементы, равные заданному объекту. -
delete_at: удаляет элемент по заданному смещению. -
delete_if: удаляет элементы, указанные заданным блоком. -
keep_if: удаляет элементы, не указанные заданным блоком. -
pop: удаляет и возвращает последний элемент. -
reject!: удаляет элементы, указанные заданным блоком. -
select!(псевдонимfilter!): удаляет элементы, не указанные заданным блоком. -
shift: удаляет и возвращает первый элемент. -
slice!: удаляет и возвращает последовательность элементов. -
uniq!: удаляет дубликаты.
Методы для объединения
-
&: возвращает массив с элементами, присутствующими и вself, и в заданном массиве. -
+: возвращает массив, содержащий все элементыself, за которыми следуют все элементы заданного массива. -
-: возвращает массив со всеми элементамиself, отсутствующими в заданном массиве. -
|: возвращает массив со всеми элементамиselfи заданного массива без дубликатов. -
difference: возвращает массив со всеми элементамиself, отсутствующими во всех заданных массивах. -
intersection: возвращает массив с элементами, присутствующими и вself, и в каждом из заданных массивов. -
product: возвращает или передаёт блоку все комбинации элементовselfи заданных массивов. -
reverse: возвращает массив со всеми элементамиselfв обратном порядке. -
union: возвращает массив со всеми элементамиselfи заданных массивов без дубликатов.
Методы для перебора
-
combination: вызывает заданный блок для комбинаций элементовself; в одной комбинации один и тот же элемент используется не более одного раза. -
cycle: вызывает заданный блок для каждого элемента и повторяет это указанное число раз или бесконечно. -
each: передаёт каждый элемент заданному блоку. -
each_index: передаёт индекс каждого элемента заданному блоку. -
permutation: вызывает заданный блок для перестановок элементовself; в одной перестановке один и тот же элемент используется не более одного раза. -
repeated_combination: вызывает заданный блок для комбинаций элементовself; в комбинации один и тот же элемент может использоваться несколько раз. -
repeated_permutation: вызывает заданный блок для перестановок элементовself; в перестановке один и тот же элемент может использоваться несколько раз. -
reverse_each: передаёт каждый элемент заданному блоку в обратном порядке.
Методы для преобразования
-
collect(псевдонимmap): Возвращает массив, содержащий значение, возвращённое блоком для каждого элемента. -
collect!(псевдонимmap!): Заменяет каждый элемент значением, возвращённым блоком. -
flatten: Возвращает массив, представляющий собой рекурсивно уплощённую версиюself. -
inspect(псевдонимto_s): Возвращает новыйString, содержащий элементы. -
join: Возвращает новыйString, содержащий элементы, объединённые разделителем полей. -
to_a: Возвращаетselfили новый массив, содержащий все элементы. -
to_ary: Возвращаетself. -
to_h: Возвращает новый хеш, сформированный из элементов. -
transpose: Транспонируетself, который должен быть массивом массивов. -
zip: Возвращает новый массив массивов, содержащийselfи заданные массивы.
Другие методы
-
*: Возвращает одно из следующего:-
Если аргумент — целое число
n, новый массив, представляющий собой конкатенациюnкопийself. -
Если аргумент — строка
field_separator, новую строку, эквивалентнуюjoin(field_separator).
-
-
pack: Упаковывает элементы в двоичную последовательность. -
sum: Возвращает сумму элементов согласно+или заданному блоку.
Общедоступные методы класса
static VALUE
rb_ary_s_create(int argc, VALUE *argv, VALUE klass)
{
VALUE ary = ary_new(klass, argc);
if (argc > 0 && argv) {
ary_memcpy(ary, 0, argc, argv);
ARY_SET_LEN(ary, argc);
}
return ary;
} Возвращает новый массив, заполненный заданными объектами:
Array[1, 'a', /^A/] # => [1, "a", /^A/] Array[] # => [] Array.[](1, 'a', /^A/) # => [1, "a", /^A/]
Связанные методы: см. Методы создания массива.
static VALUE
rb_ary_initialize(int argc, VALUE *argv, VALUE ary)
{
long len;
VALUE size, val;
rb_ary_modify(ary);
if (argc == 0) {
rb_ary_reset(ary);
RUBY_ASSERT(ARY_EMBED_P(ary));
RUBY_ASSERT(ARY_EMBED_LEN(ary) == 0);
if (rb_block_given_p()) {
rb_warning("given block not used");
}
return ary;
}
rb_scan_args(argc, argv, "02", &size, &val);
if (argc == 1 && !FIXNUM_P(size)) {
val = rb_check_array_type(size);
if (!NIL_P(val)) {
rb_ary_replace(ary, val);
return ary;
}
}
len = NUM2LONG(size);
/* NUM2LONG() may call size.to_int, ary can be frozen, modified, etc */
if (len < 0) {
rb_raise(rb_eArgError, "negative array size");
}
if (len > ARY_MAX_SIZE) {
rb_raise(rb_eArgError, "array size too big");
}
/* recheck after argument conversion */
rb_ary_modify(ary);
ary_resize_capa(ary, len);
if (rb_block_given_p()) {
long i;
if (argc == 2) {
rb_warn("block supersedes default value argument");
}
for (i=0; i<len; i++) {
rb_ary_store(ary, i, rb_yield(LONG2NUM(i)));
ARY_SET_LEN(ary, i + 1);
}
}
else {
ary_memfill(ary, 0, len, val);
ARY_SET_LEN(ary, len);
}
return ary;
} Возвращает новый массив.
Если блок и аргумент не заданы, возвращает новый пустой массив:
Array.new # => []
Если блок не задан, а в качестве аргумента передан массив, возвращает новый массив с теми же элементами:
Array.new([:foo, 'bar', 2]) # => [:foo, "bar", 2]
Если блок не задан, а в качестве аргумента передано целое число, возвращает новый массив, содержащий указанное число экземпляров заданного default_value:
Array.new(0) # => [] Array.new(3) # => [nil, nil, nil] Array.new(2, 3) # => [3, 3]
Если задан блок, возвращает массив заданного size; вызывает блок для каждого index в диапазоне (0...size); элемент массива с этим index равен значению, возвращённому блоком:
Array.new(3) {|index| "Element #{index}" } # => ["Element 0", "Element 1", "Element 2"]
Распространённая ошибка новичков в Ruby — передавать выражение в качестве default_value:
array = Array.new(2, {})
array # => [{}, {}]
array[0][:a] = 1
array # => [{a: 1}, {a: 1}], as array[0] and array[1] are same object
Чтобы элементы массива были уникальными, следует передать блок:
array = Array.new(2) { {} }
array # => [{}, {}]
array[0][:a] = 1
array # => [{a: 1}, {}], as array[0] and array[1] are different objects
Вызывает TypeError, если первый аргумент не является массивом или объектом, преобразуемым в целое число. Вызывает ArgumentError, если первый аргумент — отрицательное целое число.
Связанные методы: см. Методы создания массива.
static VALUE
rb_ary_s_try_convert(VALUE dummy, VALUE ary)
{
return rb_check_array_type(ary);
} Пытается вернуть массив на основе заданного object.
Если object является массивом, возвращает object.
В противном случае, если object отвечает на вызов :to_ary, вызывает object.to_ary: если возвращаемое значение является массивом или nil, возвращает это значение; иначе вызывает TypeError.
В противном случае возвращает nil.
Связанные методы: см. Методы создания массива.
Общедоступные методы экземпляра
static VALUE
rb_ary_and(VALUE ary1, VALUE ary2)
{
VALUE hash, ary3, v;
st_data_t vv;
long i;
ary2 = to_ary(ary2);
ary3 = rb_ary_new();
if (RARRAY_LEN(ary1) == 0 || RARRAY_LEN(ary2) == 0) return ary3;
if (RARRAY_LEN(ary1) <= SMALL_ARRAY_LEN && RARRAY_LEN(ary2) <= SMALL_ARRAY_LEN) {
for (i=0; i<RARRAY_LEN(ary1); i++) {
v = RARRAY_AREF(ary1, i);
if (!rb_ary_includes_by_eql(ary2, v)) continue;
if (rb_ary_includes_by_eql(ary3, v)) continue;
rb_ary_push(ary3, v);
}
return ary3;
}
hash = ary_make_hash(ary2);
for (i=0; i<RARRAY_LEN(ary1); i++) {
v = RARRAY_AREF(ary1, i);
vv = (st_data_t)v;
if (rb_hash_stlike_delete(hash, &vv, 0)) {
rb_ary_push(ary3, v);
}
}
return ary3;
} Возвращает новый массив, содержащий пересечение self и other_array, то есть элементы, которые присутствуют и в self, и в other_array:
[0, 1, 2, 3] & [1, 2] # => [1, 2]
Дубликаты исключаются:
[0, 1, 1, 0] & [0, 1] # => [0, 1]
Порядок элементов из self сохраняется:
[0, 1, 2] & [3, 2, 1, 0] # => [0, 1, 2]
Общие элементы определяются с помощью метода eql? (определённого для каждого элемента self).
Связано: см. Методы объединения.
static VALUE
rb_ary_times(VALUE ary, VALUE times)
{
VALUE ary2, tmp;
const VALUE *ptr;
long t, len;
tmp = rb_check_string_type(times);
if (!NIL_P(tmp)) {
return rb_ary_join(ary, tmp);
}
len = NUM2LONG(times);
if (len == 0) {
ary2 = ary_new(rb_cArray, 0);
goto out;
}
if (len < 0) {
rb_raise(rb_eArgError, "negative argument");
}
if (ARY_MAX_SIZE/len < RARRAY_LEN(ary)) {
rb_raise(rb_eArgError, "argument too big");
}
len *= RARRAY_LEN(ary);
ary2 = ary_new(rb_cArray, len);
ARY_SET_LEN(ary2, len);
ptr = RARRAY_CONST_PTR(ary);
t = RARRAY_LEN(ary);
if (0 < t) {
ary_memcpy(ary2, 0, t, ptr);
while (t <= len/2) {
ary_memcpy(ary2, t, t, RARRAY_CONST_PTR(ary2));
t *= 2;
}
if (t < len) {
ary_memcpy(ary2, t, len-t, RARRAY_CONST_PTR(ary2));
}
}
out:
return ary2;
} Если задан аргумент n — неотрицательное целое число, возвращает новый массив, созданный конкатенацией n копий self:
a = ['x', 'y'] a * 3 # => ["x", "y", "x", "y", "x", "y"]
Если задан строковый аргумент string_separator, эквивалентно self.join(string_separator):
[0, [0, 1], {foo: 0}] * ', ' # => "0, 0, 1, {foo: 0}"
VALUE
rb_ary_plus(VALUE x, VALUE y)
{
VALUE z;
long len, xlen, ylen;
y = to_ary(y);
xlen = RARRAY_LEN(x);
ylen = RARRAY_LEN(y);
len = xlen + ylen;
z = rb_ary_new2(len);
ary_memcpy(z, 0, xlen, RARRAY_CONST_PTR(x));
ary_memcpy(z, xlen, ylen, RARRAY_CONST_PTR(y));
ARY_SET_LEN(z, len);
return z;
} Возвращает новый массив, содержащий все элементы self, за которыми следуют все элементы other_array:
a = [0, 1] + [2, 3] a # => [0, 1, 2, 3]
Связано: см. Методы объединения.
VALUE
rb_ary_diff(VALUE ary1, VALUE ary2)
{
VALUE ary3;
VALUE hash;
long i;
ary2 = to_ary(ary2);
if (RARRAY_LEN(ary2) == 0) { return ary_make_shared_copy(ary1); }
ary3 = rb_ary_new();
if (RARRAY_LEN(ary1) <= SMALL_ARRAY_LEN || RARRAY_LEN(ary2) <= SMALL_ARRAY_LEN) {
for (i=0; i<RARRAY_LEN(ary1); i++) {
VALUE elt = rb_ary_elt(ary1, i);
if (rb_ary_includes_by_eql(ary2, elt)) continue;
rb_ary_push(ary3, elt);
}
return ary3;
}
hash = ary_make_hash(ary2);
for (i=0; i<RARRAY_LEN(ary1); i++) {
if (rb_hash_stlike_lookup(hash, RARRAY_AREF(ary1, i), NULL)) continue;
rb_ary_push(ary3, rb_ary_elt(ary1, i));
}
return ary3;
} Возвращает новый массив, содержащий только те элементы self, которых нет в other_array; порядок элементов из self сохраняется:
[0, 1, 1, 2, 1, 1, 3, 1, 1] - [1] # => [0, 2, 3] [0, 1, 1, 2, 1, 1, 3, 1, 1] - [3, 2, 0, :foo] # => [1, 1, 1, 1, 1, 1] [0, 1, 2] - [:foo] # => [0, 1, 2]
Элементы сравниваются с помощью метода eql? (определённого для каждого элемента self).
Связано: см. Методы объединения.
VALUE
rb_ary_push(VALUE ary, VALUE item)
{
long idx = RARRAY_LEN((ary_verify(ary), ary));
VALUE target_ary = ary_ensure_room_for_push(ary, 1);
RARRAY_PTR_USE(ary, ptr, {
RB_OBJ_WRITE(target_ary, &ptr[idx], item);
});
ARY_SET_LEN(ary, idx + 1);
ary_verify(ary);
return ary;
} Добавляет object в качестве последнего элемента в self; возвращает self:
[:foo, 'bar', 2] << :baz # => [:foo, "bar", 2, :baz]
Добавляет object как единый элемент, даже если это другой массив:
[:foo, 'bar', 2] << [3, 4] # => [:foo, "bar", 2, [3, 4]]
Связано: см. Методы присваивания.
VALUE
rb_ary_cmp(VALUE ary1, VALUE ary2)
{
long len;
VALUE v;
ary2 = rb_check_array_type(ary2);
if (NIL_P(ary2)) return Qnil;
if (ary1 == ary2) return INT2FIX(0);
v = rb_exec_recursive_paired(recursive_cmp, ary1, ary2, ary2);
if (!UNDEF_P(v)) return v;
len = RARRAY_LEN(ary1) - RARRAY_LEN(ary2);
if (len == 0) return INT2FIX(0);
if (len > 0) return INT2FIX(1);
return INT2FIX(-1);
} Возвращает -1, 0 или 1 в зависимости от того, считается ли self меньше, равно или больше other_array.
Последовательно перебирает каждый индекс i в (0...self.size):
-
Вычисляет
result[i]какself[i] <=> other_array[i]. -
Немедленно возвращает 1, если
result[i]равно 1:[0, 1, 2] <=> [0, 0, 2] # => 1
-
Немедленно возвращает -1, если
result[i]равно -1:[0, 1, 2] <=> [0, 2, 2] # => -1
-
Продолжает выполнение, если
result[i]равно 0.
Если каждое result равно 0, возвращает self.size <=> other_array.size (см. Integer#<=>):
[0, 1, 2] <=> [0, 1] # => 1 [0, 1, 2] <=> [0, 1, 2] # => 0 [0, 1, 2] <=> [0, 1, 2, 3] # => -1
Обратите внимание: если other_array больше self, его конечные элементы не влияют на результат:
[0, 1, 2] <=> [0, 1, 2, -3] # => -1 [0, 1, 2] <=> [0, 1, 2, 0] # => -1 [0, 1, 2] <=> [0, 1, 2, 3] # => -1
Связано: см. Методы сравнения.
static VALUE
rb_ary_equal(VALUE ary1, VALUE ary2)
{
if (ary1 == ary2) return Qtrue;
if (!RB_TYPE_P(ary2, T_ARRAY)) {
if (!rb_respond_to(ary2, idTo_ary)) {
return Qfalse;
}
return rb_equal(ary2, ary1);
}
if (RARRAY_LEN(ary1) != RARRAY_LEN(ary2)) return Qfalse;
if (RARRAY_CONST_PTR(ary1) == RARRAY_CONST_PTR(ary2)) return Qtrue;
return rb_exec_recursive_paired(recursive_equal, ary1, ary2, ary2);
} Возвращает, совпадают ли оба условия:
-
selfиother_arrayимеют одинаковый размер. -
Соответствующие элементы совпадают, то есть для каждого индекса
iв(0...self.size)выполняетсяself[i] == other_array[i].
Примеры:
[:foo, 'bar', 2] == [:foo, 'bar', 2] # => true [:foo, 'bar', 2] == [:foo, 'bar', 2.0] # => true [:foo, 'bar', 2] == [:foo, 'bar'] # => false # Different sizes. [:foo, 'bar', 2] == [:foo, 'bar', 3] # => false # Different elements.
Этот метод отличается от метода Array#eql?, который сравнивает элементы с помощью Object#eql?.
Связано: см. Методы сравнения.
VALUE
rb_ary_aref(int argc, const VALUE *argv, VALUE ary)
{
rb_check_arity(argc, 1, 2);
if (argc == 2) {
return rb_ary_aref2(ary, argv[0], argv[1]);
}
return rb_ary_aref1(ary, argv[0]);
} Возвращает элементы из self; не изменяет self.
Кратко:
a = [:foo, 'bar', 2] # Single argument index: returns one element. a[0] # => :foo # Zero-based index. a[-1] # => 2 # Negative index counts backwards from end. # Arguments start and length: returns an array. a[1, 2] # => ["bar", 2] a[-2, 2] # => ["bar", 2] # Negative start counts backwards from end. # Single argument range: returns an array. a[0..1] # => [:foo, "bar"] a[0..-2] # => [:foo, "bar"] # Negative range-begin counts backwards from end. a[-2..2] # => ["bar", 2] # Negative range-end counts backwards from end.
Если задан один целочисленный аргумент index, возвращает элемент со смещением index:
a = [:foo, 'bar', 2] a[0] # => :foo a[2] # => 2 a # => [:foo, "bar", 2]
Если index отрицателен, отсчёт ведётся с конца self:
a = [:foo, 'bar', 2] a[-1] # => 2 a[-2] # => "bar"
Если index выходит за допустимый диапазон, возвращает nil.
Если заданы два аргумента Integer — start и length, возвращает новый массив размера length, содержащий последовательные элементы, начиная со смещения start:
a = [:foo, 'bar', 2] a[0, 2] # => [:foo, "bar"] a[1, 2] # => ["bar", 2]
Если start + length больше self.length, возвращает все элементы от смещения start до конца:
a = [:foo, 'bar', 2] a[0, 4] # => [:foo, "bar", 2] a[1, 3] # => ["bar", 2] a[2, 2] # => [2]
Если start == self.size и length >= 0, возвращает новый пустой массив.
Если length отрицателен, возвращает nil.
Если задан один аргумент Range — range, обрабатывает range.min как описано выше для start, а range.size — как описано выше для length:
a = [:foo, 'bar', 2] a[0..1] # => [:foo, "bar"] a[1..2] # => ["bar", 2]
Особый случай: если range.start == a.size, возвращает новый пустой массив.
Если range.end отрицателен, вычисляет конечный индекс от конца:
a = [:foo, 'bar', 2] a[0..-1] # => [:foo, "bar", 2] a[0..-2] # => [:foo, "bar"] a[0..-3] # => [:foo]
Если range.start отрицателен, вычисляет начальный индекс от конца:
a = [:foo, 'bar', 2] a[-1..2] # => [2] a[-2..2] # => ["bar", 2] a[-3..2] # => [:foo, "bar", 2]
Если range.start больше размера массива, возвращает nil.
a = [:foo, 'bar', 2] a[4..1] # => nil a[4..0] # => nil a[4..-1] # => nil
Если задан один аргумент Enumerator::ArithmeticSequence — aseq, возвращает массив элементов, соответствующих индексам, полученным из последовательности.
a = ['--', 'data1', '--', 'data2', '--', 'data3'] a[(1..).step(2)] # => ["data1", "data2", "data3"]
В отличие от извлечения с помощью диапазона, если начало или конец арифметической последовательности выходит за размер массива, возникает исключение RangeError.
a = ['--', 'data1', '--', 'data2', '--', 'data3'] a[(1..11).step(2)] # RangeError (((1..11).step(2)) out of range) a[(7..).step(2)] # RangeError (((7..).step(2)) out of range)
Если задан один аргумент, тип которого не входит в перечисленные, метод пытается преобразовать его в Integer и вызывает исключение, если это невозможно:
a = [:foo, 'bar', 2] # Raises TypeError (no implicit conversion of Symbol into Integer): a[:foo]
Связано: см. Методы получения элементов.
static VALUE
rb_ary_aset(int argc, VALUE *argv, VALUE ary)
{
long offset, beg, len;
rb_check_arity(argc, 2, 3);
rb_ary_modify_check(ary);
if (argc == 3) {
beg = NUM2LONG(argv[0]);
len = NUM2LONG(argv[1]);
return ary_aset_by_rb_ary_splice(ary, beg, len, argv[2]);
}
if (FIXNUM_P(argv[0])) {
offset = FIX2LONG(argv[0]);
return ary_aset_by_rb_ary_store(ary, offset, argv[1]);
}
if (rb_range_beg_len(argv[0], &beg, &len, RARRAY_LEN(ary), 1)) {
/* check if idx is Range */
return ary_aset_by_rb_ary_splice(ary, beg, len, argv[1]);
}
offset = NUM2LONG(argv[0]);
return ary_aset_by_rb_ary_store(ary, offset, argv[1]);
} Присваивает элементы в self на основе заданного object; возвращает object.
Кратко:
a_orig = [:foo, 'bar', 2] # With argument index. a = a_orig.dup a[0] = 'foo' # => "foo" a # => ["foo", "bar", 2] a = a_orig.dup a[7] = 'foo' # => "foo" a # => [:foo, "bar", 2, nil, nil, nil, nil, "foo"] # With arguments start and length. a = a_orig.dup a[0, 2] = 'foo' # => "foo" a # => ["foo", 2] a = a_orig.dup a[6, 50] = 'foo' # => "foo" a # => [:foo, "bar", 2, nil, nil, nil, "foo"] # With argument range. a = a_orig.dup a[0..1] = 'foo' # => "foo" a # => ["foo", 2] a = a_orig.dup a[6..50] = 'foo' # => "foo" a # => [:foo, "bar", 2, nil, nil, nil, "foo"]
Если задан аргумент Integer — index, присваивает object элементу в self.
Если index неотрицателен, присваивает object элементу со смещением index:
a = [:foo, 'bar', 2] a[0] = 'foo' # => "foo" a # => ["foo", "bar", 2]
Если index больше self.length, расширяет массив:
a = [:foo, 'bar', 2] a[7] = 'foo' # => "foo" a # => [:foo, "bar", 2, nil, nil, nil, nil, "foo"]
Если index отрицателен, отсчёт ведётся с конца массива:
a = [:foo, 'bar', 2] a[-1] = 'two' # => "two" a # => [:foo, "bar", "two"]
Если заданы аргументы Integer — start и length, а object не является массивом, удаляет length - 1 элементов, начиная со смещения start, и присваивает object по смещению start:
a = [:foo, 'bar', 2] a[0, 2] = 'foo' # => "foo" a # => ["foo", 2]
Если start отрицателен, отсчёт ведётся с конца массива:
a = [:foo, 'bar', 2] a[-2, 2] = 'foo' # => "foo" a # => [:foo, "foo"]
Если start неотрицателен и находится за пределами массива ( >= self.size), расширяет массив значениями nil, присваивает object по смещению start и игнорирует length:
a = [:foo, 'bar', 2] a[6, 50] = 'foo' # => "foo" a # => [:foo, "bar", 2, nil, nil, nil, "foo"]
Если length равно нулю, сдвигает элементы, начиная со смещения start, и присваивает object по смещению start:
a = [:foo, 'bar', 2] a[1, 0] = 'foo' # => "foo" a # => [:foo, "foo", "bar", 2]
Если length слишком велико для существующего массива, массив не расширяется:
a = [:foo, 'bar', 2] a[1, 5] = 'foo' # => "foo" a # => [:foo, "foo"]
Если задан аргумент Range — range, а object не является массивом, удаляет length - 1 элементов, начиная со смещения start, и присваивает object по смещению start:
a = [:foo, 'bar', 2] a[0..1] = 'foo' # => "foo" a # => ["foo", 2]
Если range.begin отрицателен, отсчёт ведётся с конца массива:
a = [:foo, 'bar', 2] a[-2..2] = 'foo' # => "foo" a # => [:foo, "foo"]
Если длина массива меньше range.begin, расширяет массив значениями nil, присваивает object по смещению range.begin и игнорирует length:
a = [:foo, 'bar', 2] a[6..50] = 'foo' # => "foo" a # => [:foo, "bar", 2, nil, nil, nil, "foo"]
Если range.end равно нулю, сдвигает элементы, начиная со смещения start, и присваивает object по смещению start:
a = [:foo, 'bar', 2] a[1..0] = 'foo' # => "foo" a # => [:foo, "foo", "bar", 2]
Если range.end отрицателен, присваивает object по смещению start, сохраняет range.end.abs -1 следующих за ним элементов и удаляет остальные:
a = [:foo, 'bar', 2] a[1..-1] = 'foo' # => "foo" a # => [:foo, "foo"] a = [:foo, 'bar', 2] a[1..-2] = 'foo' # => "foo" a # => [:foo, "foo", 2] a = [:foo, 'bar', 2] a[1..-3] = 'foo' # => "foo" a # => [:foo, "foo", "bar", 2] a = [:foo, 'bar', 2]
Если range.end слишком велико для существующего массива, заменяет элементы массива, но не расширяет массив значениями nil:
a = [:foo, 'bar', 2] a[1..5] = 'foo' # => "foo" a # => [:foo, "foo"]
Связано: см. Методы присваивания.
static VALUE
rb_ary_or(VALUE ary1, VALUE ary2)
{
VALUE hash;
ary2 = to_ary(ary2);
if (RARRAY_LEN(ary1) + RARRAY_LEN(ary2) <= SMALL_ARRAY_LEN) {
VALUE ary3 = rb_ary_new();
rb_ary_union(ary3, ary1);
rb_ary_union(ary3, ary2);
return ary3;
}
hash = ary_make_hash(ary1);
rb_ary_union_hash(hash, ary2);
return rb_hash_values(hash);
} Возвращает объединение self и other_array; дубликаты удаляются, порядок сохраняется, элементы сравниваются с помощью eql?:
[0, 1] | [2, 3] # => [0, 1, 2, 3] [0, 1, 1] | [2, 2, 3] # => [0, 1, 2, 3] [0, 1, 2] | [3, 2, 1, 0] # => [0, 1, 2, 3]
Связано: см. Методы объединения.
static VALUE
rb_ary_all_p(int argc, VALUE *argv, VALUE ary)
{
long i, len = RARRAY_LEN(ary);
rb_check_arity(argc, 0, 1);
if (!len) return Qtrue;
if (argc) {
if (rb_block_given_p()) {
rb_warn("given block not used");
}
for (i = 0; i < RARRAY_LEN(ary); ++i) {
if (!RTEST(rb_funcall(argv[0], idEqq, 1, RARRAY_AREF(ary, i)))) return Qfalse;
}
}
else if (!rb_block_given_p()) {
for (i = 0; i < len; ++i) {
if (!RTEST(RARRAY_AREF(ary, i))) return Qfalse;
}
}
else {
for (i = 0; i < RARRAY_LEN(ary); ++i) {
if (!RTEST(rb_yield(RARRAY_AREF(ary, i)))) return Qfalse;
}
}
return Qtrue;
} Возвращает, удовлетворяет ли каждый элемент self заданному критерию.
Если блок и аргумент не заданы, возвращает, являются ли истинными значения всех элементов self:
[[], {}, '', 0, 0.0, Object.new].all? # => true # All truthy objects.
[[], {}, '', 0, 0.0, nil].all? # => false # nil is not truthy.
[[], {}, '', 0, 0.0, false].all? # => false # false is not truthy.
Если задан аргумент object, возвращает, выполняется ли object === ele для каждого элемента ele в self:
[0, 0, 0].all?(0) # => true [0, 1, 2].all?(1) # => false ['food', 'fool', 'foot'].all?(/foo/) # => true ['food', 'drink'].all?(/foo/) # => false
Если задан блок, вызывает его для каждого элемента в self; возвращает, только ли истинные значения возвращает блок:
[0, 1, 2].all? { |ele| ele < 3 } # => true
[0, 1, 2].all? { |ele| ele < 2 } # => false
Если заданы и блок, и аргумент object, блок игнорируется, а object используется, как описано выше.
Особый случай: возвращает true, если self пуст (независимо от заданного аргумента или блока).
Связано: см. Методы проверки.
static VALUE
rb_ary_any_p(int argc, VALUE *argv, VALUE ary)
{
long i, len = RARRAY_LEN(ary);
rb_check_arity(argc, 0, 1);
if (!len) return Qfalse;
if (argc) {
if (rb_block_given_p()) {
rb_warn("given block not used");
}
for (i = 0; i < RARRAY_LEN(ary); ++i) {
if (RTEST(rb_funcall(argv[0], idEqq, 1, RARRAY_AREF(ary, i)))) return Qtrue;
}
}
else if (!rb_block_given_p()) {
for (i = 0; i < len; ++i) {
if (RTEST(RARRAY_AREF(ary, i))) return Qtrue;
}
}
else {
for (i = 0; i < RARRAY_LEN(ary); ++i) {
if (RTEST(rb_yield(RARRAY_AREF(ary, i)))) return Qtrue;
}
}
return Qfalse;
} Возвращает, удовлетворяет ли хотя бы один элемент self заданному критерию.
Если блок и аргумент не заданы, возвращает, является ли истинным значение хотя бы одного элемента self:
[nil, false, []].any? # => true # Array object is truthy.
[nil, false, {}].any? # => true # Hash object is truthy.
[nil, false, ''].any? # => true # String object is truthy.
[nil, false].any? # => false # Nil and false are not truthy.
Если задан аргумент object, возвращает, выполняется ли object === ele хотя бы для одного элемента ele в self:
[nil, false, 0].any?(0) # => true [nil, false, 1].any?(0) # => false [nil, false, 'food'].any?(/foo/) # => true [nil, false, 'food'].any?(/bar/) # => false
Если задан блок, вызывает его для каждого элемента в self; возвращает, возвращает ли блок хотя бы одно истинное значение:
[0, 1, 2].any? {|ele| ele < 1 } # => true
[0, 1, 2].any? {|ele| ele < 0 } # => false
Если заданы и блок, и аргумент object, блок игнорируется, а object используется, как описано выше.
Особый случай: возвращает false, если self пуст (независимо от заданного аргумента или блока).
Связано: см. Методы проверки.
Добавляет каждый аргумент из objects в self; возвращает self:
a = [:foo, 'bar', 2] # => [:foo, "bar", 2] a.push(:baz, :bat) # => [:foo, "bar", 2, :baz, :bat]
Добавляет каждый аргумент как отдельный элемент, даже если это другой массив:
a = [:foo, 'bar', 2] # => [:foo, "bar", 2] a.push([:baz, :bat], [:bam, :bad]) # => [:foo, "bar", 2, [:baz, :bat], [:bam, :bad]]
Связано: см. Методы присваивания.
VALUE
rb_ary_assoc(VALUE ary, VALUE key)
{
long i;
VALUE v;
for (i = 0; i < RARRAY_LEN(ary); ++i) {
v = rb_check_array_type(RARRAY_AREF(ary, i));
if (!NIL_P(v) && RARRAY_LEN(v) > 0 &&
rb_equal(RARRAY_AREF(v, 0), key))
return v;
}
return Qnil;
} Возвращает первый элемент ele в self, для которого ele является массивом и выполняется ele[0] == object:
a = [{foo: 0}, [2, 4], [4, 5, 6], [4, 5]]
a.assoc(4) # => [4, 5, 6]
Возвращает nil, если такой элемент не найден.
Связано: Array#rassoc; см. также Методы получения элементов.
VALUE
rb_ary_at(VALUE ary, VALUE pos)
{
return rb_ary_entry(ary, NUM2LONG(pos));
} Возвращает элемент self, указанный заданным index, или nil, если такого элемента нет; index должен быть объектом, преобразуемым в целое число.
Для неотрицательного index возвращает элемент self со смещением index:
a = [:foo, 'bar', 2] a.at(0) # => :foo a.at(2) # => 2 a.at(2.0) # => 2
Для отрицательного index отсчёт ведётся с конца self:
a.at(-2) # => "bar"
Связано: Array#[]; см. также Методы получения элементов.
static VALUE
rb_ary_bsearch(VALUE ary)
{
VALUE index_result = rb_ary_bsearch_index(ary);
if (FIXNUM_P(index_result)) {
return rb_ary_entry(ary, FIX2LONG(index_result));
}
return index_result;
} Возвращает элемент из self, найденный двоичным поиском, или nil, если подходящий элемент не найден.
См. Двоичный поиск.
Связано: см. Методы получения элементов.
static VALUE
rb_ary_bsearch_index(VALUE ary)
{
long low = 0, high = RARRAY_LEN(ary), mid;
int smaller = 0, satisfied = 0;
VALUE v, val;
RETURN_ENUMERATOR(ary, 0, 0);
while (low < high) {
mid = low + ((high - low) / 2);
val = rb_ary_entry(ary, mid);
v = rb_yield(val);
if (FIXNUM_P(v)) {
if (v == INT2FIX(0)) return INT2FIX(mid);
smaller = (SIGNED_VALUE)v < 0; /* Fixnum preserves its sign-bit */
}
else if (v == Qtrue) {
satisfied = 1;
smaller = 1;
}
else if (!RTEST(v)) {
smaller = 0;
}
else if (rb_obj_is_kind_of(v, rb_cNumeric)) {
const VALUE zero = INT2FIX(0);
switch (rb_cmpint(rb_funcallv(v, id_cmp, 1, &zero), v, zero)) {
case 0: return INT2FIX(mid);
case 1: smaller = 0; break;
case -1: smaller = 1;
}
}
else {
rb_raise(rb_eTypeError, "wrong argument type %"PRIsVALUE
" (must be numeric, true, false or nil)",
rb_obj_class(v));
}
if (smaller) {
high = mid;
}
else {
low = mid + 1;
}
}
if (!satisfied) return Qnil;
return INT2FIX(low);
} Возвращает целочисленный индекс элемента из self, найденного двоичным поиском, или nil, если подходящий элемент не найден.
См. Двоичный поиск.
Связано: см. Методы получения элементов.
VALUE
rb_ary_clear(VALUE ary)
{
rb_ary_modify_check(ary);
if (ARY_SHARED_P(ary)) {
rb_ary_unshare(ary);
FL_SET_EMBED(ary);
ARY_SET_EMBED_LEN(ary, 0);
}
else {
ARY_SET_LEN(ary, 0);
if (ARY_DEFAULT_SIZE * 2 < ARY_CAPA(ary)) {
ary_resize_capa(ary, ARY_DEFAULT_SIZE * 2);
}
}
ary_verify(ary);
return ary;
} Удаляет все элементы из self; возвращает self:
a = [:foo, 'bar', 2] a.clear # => []
Связано: см. Методы удаления.
static VALUE
rb_ary_collect(VALUE ary)
{
long i;
VALUE collect;
RETURN_SIZED_ENUMERATOR(ary, 0, 0, ary_enum_length);
collect = rb_ary_new2(RARRAY_LEN(ary));
for (i = 0; i < RARRAY_LEN(ary); i++) {
rb_ary_push(collect, rb_yield(RARRAY_AREF(ary, i)));
}
return collect;
} Если задан блок, вызывает его для каждого элемента self; возвращает новый массив, элементы которого являются значениями, возвращёнными блоком:
a = [:foo, 'bar', 2]
a1 = a.map {|element| element.class }
a1 # => [Symbol, String, Integer]
Если блок не задан, возвращает новый Enumerator.
Связано: collect!; см. также Методы преобразования.
static VALUE
rb_ary_collect_bang(VALUE ary)
{
long i;
RETURN_SIZED_ENUMERATOR(ary, 0, 0, ary_enum_length);
rb_ary_modify(ary);
for (i = 0; i < RARRAY_LEN(ary); i++) {
rb_ary_store(ary, i, rb_yield(RARRAY_AREF(ary, i)));
}
return ary;
} Если задан блок, вызывает его для каждого элемента self и заменяет этот элемент значением, возвращённым блоком; возвращает self:
a = [:foo, 'bar', 2]
a.map! { |element| element.class } # => [Symbol, String, Integer]
Если блок не задан, возвращает новый Enumerator.
Связано: collect; см. также Методы преобразования.
static VALUE
rb_ary_combination(VALUE ary, VALUE num)
{
long i, n, len;
n = NUM2LONG(num);
RETURN_SIZED_ENUMERATOR(ary, 1, &num, rb_ary_combination_size);
len = RARRAY_LEN(ary);
if (n < 0 || len < n) {
/* yield nothing */
}
else if (n == 0) {
rb_yield(rb_ary_new2(0));
}
else if (n == 1) {
for (i = 0; i < RARRAY_LEN(ary); i++) {
rb_yield(rb_ary_new3(1, RARRAY_AREF(ary, i)));
}
}
else {
VALUE ary0 = ary_make_shared_copy(ary); /* private defensive copy of ary */
volatile VALUE t0;
long *stack = ALLOCV_N(long, t0, n+1);
RBASIC_CLEAR_CLASS(ary0);
combinate0(len, n, stack, ary0);
ALLOCV_END(t0);
RBASIC_SET_CLASS_RAW(ary0, rb_cArray);
}
return ary;
} Если заданы блок и положительный аргумент count — объект, преобразуемый в целое число (0 < count <= self.size), вызывает блок для каждой комбинации self размером count; возвращает self:
a = %w[a b c] # => ["a", "b", "c"]
a.combination(2) {|combination| p combination } # => ["a", "b", "c"]
Результат:
["a", "b"] ["a", "c"] ["b", "c"]
Порядок выдаваемых комбинаций не гарантируется.
Если count равно нулю, вызывает блок один раз с новым пустым массивом:
a.combination(0) {|combination| p combination }
[].combination(0) {|combination| p combination }
Результат:
[] []
Если count отрицателен или больше self.size, а self не пуст, блок не вызывается:
a.combination(-1) {|combination| fail 'Cannot happen' } # => ["a", "b", "c"]
a.combination(4) {|combination| fail 'Cannot happen' } # => ["a", "b", "c"]
Если блок не задан, возвращает новый Enumerator.
Связано: Array#permutation; см. также Методы итерации.
static VALUE
rb_ary_compact(VALUE ary)
{
ary = rb_ary_dup(ary);
rb_ary_compact_bang(ary);
return ary;
} Возвращает новый массив, содержащий только элементы nil из self; порядок элементов сохраняется:
a = [nil, 0, nil, false, nil, '', nil, [], nil, {}]
a.compact # => [0, false, "", [], {}]
Связано: Array#compact!; см. также Методы удаления.
static VALUE
rb_ary_compact_bang(VALUE ary)
{
VALUE *p, *t, *end;
long n;
rb_ary_modify(ary);
p = t = (VALUE *)RARRAY_CONST_PTR(ary); /* WB: no new reference */
end = p + RARRAY_LEN(ary);
while (t < end) {
if (NIL_P(*t)) t++;
else *p++ = *t++;
}
n = p - RARRAY_CONST_PTR(ary);
if (RARRAY_LEN(ary) == n) {
return Qnil;
}
ary_resize_smaller(ary, n);
return ary;
} Удаляет все элементы nil из self; возвращает self, если были удалены какие-либо элементы, и nil в противном случае:
a = [nil, 0, nil, false, nil, '', nil, [], nil, {}]
a.compact! # => [0, false, "", [], {}]
a # => [0, false, "", [], {}]
a.compact! # => nil
Связано: Array#compact; см. также Методы удаления.
static VALUE
rb_ary_concat_multi(int argc, VALUE *argv, VALUE ary)
{
rb_ary_modify_check(ary);
if (argc == 1) {
rb_ary_concat(ary, argv[0]);
}
else if (argc > 1) {
int i;
VALUE args = rb_ary_hidden_new(argc);
for (i = 0; i < argc; i++) {
rb_ary_concat(args, argv[i]);
}
ary_append(ary, args);
}
ary_verify(ary);
return ary;
} Добавляет в self все элементы каждого массива из other_arrays; возвращает self:
a = [0, 1] a.concat(['two', 'three'], [:four, :five], a) # => [0, 1, "two", "three", :four, :five, 0, 1]
Связано: см. Методы присваивания.
static VALUE
rb_ary_count(int argc, VALUE *argv, VALUE ary)
{
long i, n = 0;
if (rb_check_arity(argc, 0, 1) == 0) {
VALUE v;
if (!rb_block_given_p())
return LONG2NUM(RARRAY_LEN(ary));
for (i = 0; i < RARRAY_LEN(ary); i++) {
v = RARRAY_AREF(ary, i);
if (RTEST(rb_yield(v))) n++;
}
}
else {
VALUE obj = argv[0];
if (rb_block_given_p()) {
rb_warn("given block not used");
}
for (i = 0; i < RARRAY_LEN(ary); i++) {
if (rb_equal(RARRAY_AREF(ary, i), obj)) n++;
}
}
return LONG2NUM(n);
} Возвращает количество указанных элементов.
Если аргумент и блок не заданы, возвращает количество всех элементов:
[0, :one, 'two', 3, 3.0].count # => 5
Если задан аргумент object, возвращает количество элементов == по object:
[0, :one, 'two', 3, 3.0].count(3) # => 2
Если аргумент не задан, но задан блок, вызывает блок для каждого элемента; возвращает количество элементов, для которых блок возвращает истинное значение:
[0, 1, 2, 3].count {|element| element > 1 } # => 2
Если задан аргумент object и блок, выдает предупреждение, игнорирует блок и возвращает количество элементов == по object.
Связанные методы: см. Методы для проверки.
static VALUE
rb_ary_cycle(int argc, VALUE *argv, VALUE ary)
{
long n, i;
rb_check_arity(argc, 0, 1);
RETURN_SIZED_ENUMERATOR(ary, argc, argv, rb_ary_cycle_size);
if (argc == 0 || NIL_P(argv[0])) {
n = -1;
}
else {
n = NUM2LONG(argv[0]);
if (n <= 0) return Qnil;
}
while (RARRAY_LEN(ary) > 0 && (n < 0 || 0 < n--)) {
for (i=0; i<RARRAY_LEN(ary); i++) {
rb_yield(RARRAY_AREF(ary, i));
}
}
return Qnil;
} Если задан блок, он может быть вызван в зависимости от значения аргумента count; count должен быть объектом, преобразуемым в целое число, или nil.
Если count положительно, вызывает блок для каждого элемента, а затем повторяет это, пока не сделает это count раз; возвращает nil:
output = []
[0, 1].cycle(2) {|element| output.push(element) } # => nil
output # => [0, 1, 0, 1]
Если count равно нулю или отрицательно, блок не вызывается:
[0, 1].cycle(0) {|element| fail 'Cannot happen' } # => nil
[0, 1].cycle(-1) {|element| fail 'Cannot happen' } # => nil
Если count равно nil, цикл выполняется бесконечно:
# Prints 0 and 1 forever.
[0, 1].cycle {|element| puts element }
[0, 1].cycle(nil) {|element| puts element }
Если блок не задан, возвращает новый Enumerator.
Связанные методы: см. Методы для перебора.
VALUE
rb_ary_delete(VALUE ary, VALUE item)
{
VALUE v = item;
long i1, i2;
for (i1 = i2 = 0; i1 < RARRAY_LEN(ary); i1++) {
VALUE e = RARRAY_AREF(ary, i1);
if (rb_equal(e, item)) {
v = e;
continue;
}
if (i1 != i2) {
rb_ary_store(ary, i2, e);
}
i2++;
}
if (RARRAY_LEN(ary) == i2) {
if (rb_block_given_p()) {
return rb_yield(item);
}
return Qnil;
}
ary_resize_smaller(ary, i2);
ary_verify(ary);
return v;
} Удаляет из self ноль или более элементов.
Если блок не задан, удаляет из self каждый элемент ele, для которого выполняется ele == object; возвращает последний удаленный элемент:
a = [0, 1, 2, 2.0] a.delete(2) # => 2.0 a # => [0, 1]
Если элементы не удалены, возвращает nil:
a.delete(2) # => nil
Если задан блок, удаляет из self каждый элемент ele, для которого выполняется ele == object.
Если такие элементы найдены, игнорирует блок и возвращает последний удаленный элемент:
a = [0, 1, 2, 2.0]
a.delete(2) {|element| fail 'Cannot happen' } # => 2.0
a # => [0, 1]
Если такие элементы не найдены, возвращает значение, возвращенное блоком:
a.delete(2) {|element| "Element #{element} not found." }
# => "Element 2 not found."
Связанные методы: см. Методы для удаления.
static VALUE
rb_ary_delete_at_m(VALUE ary, VALUE pos)
{
return rb_ary_delete_at(ary, NUM2LONG(pos));
} Удаляет элемент self с указанным индексом index, который должен быть объектом, преобразуемым в целое число.
Если index неотрицательно, удаляет элемент со смещением index:
a = [:foo, 'bar', 2] a.delete_at(1) # => "bar" a # => [:foo, 2]
Если index отрицательно, отсчет ведется с конца массива:
a = [:foo, 'bar', 2] a.delete_at(-2) # => "bar" a # => [:foo, 2]
Если index выходит за допустимый диапазон, возвращает nil.
a = [:foo, 'bar', 2] a.delete_at(3) # => nil a.delete_at(-4) # => nil
Связанные методы: см. Методы для удаления.
static VALUE
rb_ary_delete_if(VALUE ary)
{
ary_verify(ary);
RETURN_SIZED_ENUMERATOR(ary, 0, 0, ary_enum_length);
ary_reject_bang(ary);
return ary;
} Если задан блок, вызывает его для каждого элемента self; удаляет элемент, если блок возвращает истинное значение; возвращает self:
a = [:foo, 'bar', 2, 'bat']
a.delete_if {|element| element.to_s.start_with?('b') } # => [:foo, 2]
Если блок не задан, возвращает новый Enumerator.
Связанные методы: см. Методы для удаления.
static VALUE
rb_ary_difference_multi(int argc, VALUE *argv, VALUE ary)
{
VALUE ary_diff;
long i, length;
volatile VALUE t0;
bool *is_hash = ALLOCV_N(bool, t0, argc);
ary_diff = rb_ary_new();
length = RARRAY_LEN(ary);
for (i = 0; i < argc; i++) {
argv[i] = to_ary(argv[i]);
is_hash[i] = (length > SMALL_ARRAY_LEN && RARRAY_LEN(argv[i]) > SMALL_ARRAY_LEN);
if (is_hash[i]) argv[i] = ary_make_hash(argv[i]);
}
for (i = 0; i < RARRAY_LEN(ary); i++) {
int j;
VALUE elt = rb_ary_elt(ary, i);
for (j = 0; j < argc; j++) {
if (is_hash[j]) {
if (rb_hash_stlike_lookup(argv[j], elt, NULL))
break;
}
else {
if (rb_ary_includes_by_eql(argv[j], elt)) break;
}
}
if (j == argc) rb_ary_push(ary_diff, elt);
}
ALLOCV_END(t0);
return ary_diff;
} Возвращает новый массив, содержащий только те элементы из self, которые не найдены ни в одном из заданных other_arrays; элементы сравниваются с помощью eql?; порядок элементов из self сохраняется:
[0, 1, 1, 2, 1, 1, 3, 1, 1].difference([1]) # => [0, 2, 3] [0, 1, 2, 3].difference([3, 0], [1, 3]) # => [2] [0, 1, 2].difference([4]) # => [0, 1, 2] [0, 1, 2].difference # => [0, 1, 2]
Если аргументы не заданы, возвращает копию self.
Связанные методы: Array#-; см. также Методы для объединения.
static VALUE
rb_ary_dig(int argc, VALUE *argv, VALUE self)
{
rb_check_arity(argc, 1, UNLIMITED_ARGUMENTS);
self = rb_ary_at(self, *argv);
if (!--argc) return self;
++argv;
return rb_obj_dig(argc, argv, self, Qnil);
} Находит и возвращает объект во вложенном объекте, указанный с помощью index и identifiers; вложенные объекты могут быть экземплярами различных классов. См. Методы Dig.
Примеры:
a = [:foo, [:bar, :baz, [:bat, :bam]]] a.dig(1) # => [:bar, :baz, [:bat, :bam]] a.dig(1, 2) # => [:bat, :bam] a.dig(1, 2, 0) # => :bat a.dig(1, 2, 3) # => nil
Связанные методы: см. Методы для получения элементов.
static VALUE
rb_ary_drop(VALUE ary, VALUE n)
{
VALUE result;
long pos = NUM2LONG(n);
if (pos < 0) {
rb_raise(rb_eArgError, "attempt to drop negative size");
}
result = rb_ary_subseq(ary, pos, RARRAY_LEN(ary));
if (NIL_P(result)) result = rb_ary_new();
return result;
} Возвращает новый массив, содержащий все элементы self, кроме первых count, где count — неотрицательное целое число; не изменяет self.
Примеры:
a = [0, 1, 2, 3, 4, 5] a.drop(0) # => [0, 1, 2, 3, 4, 5] a.drop(1) # => [1, 2, 3, 4, 5] a.drop(2) # => [2, 3, 4, 5] a.drop(9) # => []
Связанные методы: см. Методы для получения элементов.
static VALUE
rb_ary_drop_while(VALUE ary)
{
long i;
RETURN_ENUMERATOR(ary, 0, 0);
for (i = 0; i < RARRAY_LEN(ary); i++) {
if (!RTEST(rb_yield(RARRAY_AREF(ary, i)))) break;
}
return rb_ary_drop(ary, LONG2FIX(i));
} Если задан блок, вызывает его для каждого последующего элемента self; останавливается, если блок возвращает false или nil; возвращает новый массив, исключая элементы, для которых блок вернул истинное значение; не изменяет self:
a = [0, 1, 2, 3, 4, 5]
a.drop_while {|element| element < 3 } # => [3, 4, 5]
Если блок не задан, возвращает новый Enumerator.
Связанные методы: см. Методы для получения элементов.
VALUE
rb_ary_each(VALUE ary)
{
long i;
ary_verify(ary);
RETURN_SIZED_ENUMERATOR(ary, 0, 0, ary_enum_length);
for (i=0; i<RARRAY_LEN(ary); i++) {
rb_yield(RARRAY_AREF(ary, i));
}
return ary;
} Если задан блок, перебирает элементы self, передавая каждый элемент блоку; возвращает self:
a = [:foo, 'bar', 2]
a.each {|element| puts "#{element.class} #{element}" }
Вывод:
Symbol foo String bar Integer 2
Позволяет изменять массив во время перебора:
a = [:foo, 'bar', 2]
a.each {|element| puts element; a.clear if element.to_s.start_with?('b') }
Вывод:
foo bar
Если блок не задан, возвращает новый Enumerator.
Связанные методы: см. Методы для перебора.
static VALUE
rb_ary_each_index(VALUE ary)
{
long i;
RETURN_SIZED_ENUMERATOR(ary, 0, 0, ary_enum_length);
for (i=0; i<RARRAY_LEN(ary); i++) {
rb_yield(LONG2NUM(i));
}
return ary;
} Если задан блок, перебирает элементы self, передавая блоку каждый индекс массива; возвращает self:
a = [:foo, 'bar', 2]
a.each_index {|index| puts "#{index} #{a[index]}" }
Вывод:
0 foo 1 bar 2 2
Позволяет изменять массив во время перебора:
a = [:foo, 'bar', 2]
a.each_index {|index| puts index; a.clear if index > 0 }
a # => []
Вывод:
0 1
Если блок не задан, возвращает новый Enumerator.
Связанные методы: см. Методы для перебора.
static VALUE
rb_ary_empty_p(VALUE ary)
{
return RBOOL(RARRAY_LEN(ary) == 0);
} Возвращает true, если количество элементов в self равно нулю, и false в противном случае.
Связанные методы: см. Методы для проверки.
static VALUE
rb_ary_eql(VALUE ary1, VALUE ary2)
{
if (ary1 == ary2) return Qtrue;
if (!RB_TYPE_P(ary2, T_ARRAY)) return Qfalse;
if (RARRAY_LEN(ary1) != RARRAY_LEN(ary2)) return Qfalse;
if (RARRAY_CONST_PTR(ary1) == RARRAY_CONST_PTR(ary2)) return Qtrue;
return rb_exec_recursive_paired(recursive_eql, ary1, ary2, ary2);
} Возвращает true, если self и other_array имеют одинаковый размер и для каждого индекса i в self выполняется self[i].eql?(other_array[i]):
a0 = [:foo, 'bar', 2] a1 = [:foo, 'bar', 2] a1.eql?(a0) # => true
В противном случае возвращает false.
Этот метод отличается от метода Array#==, который сравнивает с помощью метода Object#==.
Связанные методы: см. Методы для проверки.
static VALUE
rb_ary_fetch(int argc, VALUE *argv, VALUE ary)
{
VALUE pos, ifnone;
long block_given;
long idx;
rb_scan_args(argc, argv, "11", &pos, &ifnone);
block_given = rb_block_given_p();
if (block_given && argc == 2) {
rb_warn("block supersedes default value argument");
}
idx = NUM2LONG(pos);
if (idx < 0) {
idx += RARRAY_LEN(ary);
}
if (idx < 0 || RARRAY_LEN(ary) <= idx) {
if (block_given) return rb_yield(pos);
if (argc == 1) {
rb_raise(rb_eIndexError, "index %ld outside of array bounds: %ld...%ld",
idx - (idx < 0 ? RARRAY_LEN(ary) : 0), -RARRAY_LEN(ary), RARRAY_LEN(ary));
}
return ifnone;
}
return RARRAY_AREF(ary, idx);
} Возвращает элемент self со смещением index, если index находится в допустимом диапазоне; index должен быть объектом, преобразуемым в целое число.
Если задан единственный аргумент index и блок не задан, возвращает элемент со смещением index:
a = [:foo, 'bar', 2] a.fetch(1) # => "bar" a.fetch(1.1) # => "bar"
Если index отрицательно, отсчет ведется с конца массива:
a = [:foo, 'bar', 2] a.fetch(-1) # => 2 a.fetch(-2) # => "bar"
Если заданы аргументы index и default_value (которым может быть любой объект), а блок не задан, возвращает default_value, если index выходит за допустимый диапазон:
a = [:foo, 'bar', 2] a.fetch(1, nil) # => "bar" a.fetch(3, :foo) # => :foo
Если задан аргумент index и блок, возвращает элемент со смещением index, если индекс находится в допустимом диапазоне (и блок не вызывается); в противном случае вызывает блок с индексом и возвращает его результат:
a = [:foo, 'bar', 2]
a.fetch(1) {|index| raise 'Cannot happen' } # => "bar"
a.fetch(50) {|index| "Value for #{index}" } # => "Value for 50"
Связанные методы: см. Методы для получения элементов.
# File array.rb, line 210
def fetch_values(*indexes, &block)
indexes.map! { |i| fetch(i, &block) }
indexes
end Если блок не задан, возвращает новый массив, содержащий элементы self со смещениями, заданными в indexes. Каждый из indexes должен быть объектом, преобразуемым в целое число:
a = [:foo, :bar, :baz] a.fetch_values(2, 0) # => [:baz, :foo] a.fetch_values(2.1, 0) # => [:baz, :foo] a.fetch_values # => []
Для отрицательного индекса отсчет ведется с конца массива:
a.fetch_values(-2, -1) # [:bar, :baz]
Если блок не задан, при выходе любого индекса за допустимый диапазон возникает исключение.
Если задан блок, для каждого индекса:
-
Если индекс находится в допустимом диапазоне, используется элемент из
self(как описано выше). -
В противном случае блок вызывается с индексом, а его возвращаемое значение используется.
Пример:
a = [:foo, :bar, :baz]
a.fetch_values(1, 0, 42, 777) { |index| index.to_s }
# => [:bar, :foo, "42", "777"]
Связанные методы: см. Методы для получения элементов.
static VALUE
rb_ary_fill(int argc, VALUE *argv, VALUE ary)
{
VALUE item = Qundef, arg1, arg2;
long beg = 0, end = 0, len = 0;
if (rb_block_given_p()) {
rb_scan_args(argc, argv, "02", &arg1, &arg2);
argc += 1; /* hackish */
}
else {
rb_scan_args(argc, argv, "12", &item, &arg1, &arg2);
}
switch (argc) {
case 1:
beg = 0;
len = RARRAY_LEN(ary);
break;
case 2:
if (rb_range_beg_len(arg1, &beg, &len, RARRAY_LEN(ary), 1)) {
break;
}
/* fall through */
case 3:
beg = NIL_P(arg1) ? 0 : NUM2LONG(arg1);
if (beg < 0) {
beg = RARRAY_LEN(ary) + beg;
if (beg < 0) beg = 0;
}
len = NIL_P(arg2) ? RARRAY_LEN(ary) - beg : NUM2LONG(arg2);
break;
}
rb_ary_modify(ary);
if (len < 0) {
return ary;
}
if (beg >= ARY_MAX_SIZE || len > ARY_MAX_SIZE - beg) {
rb_raise(rb_eArgError, "argument too big");
}
end = beg + len;
if (RARRAY_LEN(ary) < end) {
if (end >= ARY_CAPA(ary)) {
ary_resize_capa(ary, end);
}
ary_mem_clear(ary, RARRAY_LEN(ary), end - RARRAY_LEN(ary));
ARY_SET_LEN(ary, end);
}
if (UNDEF_P(item)) {
VALUE v;
long i;
for (i=beg; i<end; i++) {
v = rb_yield(LONG2NUM(i));
if (i>=RARRAY_LEN(ary)) break;
ARY_SET(ary, i, v);
}
}
else {
ary_memfill(ary, beg, len, item);
}
return ary;
} Заменяет выбранные элементы в self; может добавлять элементы в self; всегда возвращает self (никогда не новый массив).
Кратко:
# Non-negative start.
['a', 'b', 'c', 'd'].fill('-', 1, 2) # => ["a", "-", "-", "d"]
['a', 'b', 'c', 'd'].fill(1, 2) {|e| e.to_s } # => ["a", "1", "2", "d"]
# Extends with specified values if necessary.
['a', 'b', 'c', 'd'].fill('-', 3, 2) # => ["a", "b", "c", "-", "-"]
['a', 'b', 'c', 'd'].fill(3, 2) {|e| e.to_s } # => ["a", "b", "c", "3", "4"]
# Fills with nils if necessary.
['a', 'b', 'c', 'd'].fill('-', 6, 2) # => ["a", "b", "c", "d", nil, nil, "-", "-"]
['a', 'b', 'c', 'd'].fill(6, 2) {|e| e.to_s } # => ["a", "b", "c", "d", nil, nil, "6", "7"]
# For negative start, counts backwards from the end.
['a', 'b', 'c', 'd'].fill('-', -3, 3) # => ["a", "-", "-", "-"]
['a', 'b', 'c', 'd'].fill(-3, 3) {|e| e.to_s } # => ["a", "1", "2", "3"]
# Range.
['a', 'b', 'c', 'd'].fill('-', 1..2) # => ["a", "-", "-", "d"]
['a', 'b', 'c', 'd'].fill(1..2) {|e| e.to_s } # => ["a", "1", "2", "d"]
Если заданы аргументы start и count, они выбирают элементы self для замены; каждый из них должен быть объектом, преобразуемым в целое число (или nil):
-
startзадает смещение с нуля первого заменяемого элемента;nilозначает ноль. -
count— количество заменяемых подряд элементов;nilозначает «все оставшиеся».
Если задан аргумент object, для всех замен используется этот объект:
o = Object.new # => #<Object:0x0000014e7bff7600> a = ['a', 'b', 'c', 'd'] # => ["a", "b", "c", "d"] a.fill(o, 1, 2) # => ["a", #<Object:0x0000014e7bff7600>, #<Object:0x0000014e7bff7600>, "d"]
Если задан блок, он вызывается один раз для каждого заменяемого элемента; передаваемое блоку значение — это индекс заменяемого элемента (а не сам элемент); возвращаемое блоком значение заменяет элемент:
a = ['a', 'b', 'c', 'd'] # => ["a", "b", "c", "d"]
a.fill(1, 2) {|element| element.to_s } # => ["a", "1", "2", "d"]
Для аргументов start и count:
-
Если
startнеотрицательно, заменяетcountэлементов, начиная со смещенияstart:['a', 'b', 'c', 'd'].fill('-', 0, 2) # => ["-", "-", "c", "d"] ['a', 'b', 'c', 'd'].fill('-', 1, 2) # => ["a", "-", "-", "d"] ['a', 'b', 'c', 'd'].fill('-', 2, 2) # => ["a", "b", "-", "-"] ['a', 'b', 'c', 'd'].fill(0, 2) {|e| e.to_s } # => ["0", "1", "c", "d"] ['a', 'b', 'c', 'd'].fill(1, 2) {|e| e.to_s } # => ["a", "1", "2", "d"] ['a', 'b', 'c', 'd'].fill(2, 2) {|e| e.to_s } # => ["a", "b", "2", "3"]При необходимости расширяет
self:['a', 'b', 'c', 'd'].fill('-', 3, 2) # => ["a", "b", "c", "-", "-"] ['a', 'b', 'c', 'd'].fill('-', 4, 2) # => ["a", "b", "c", "d", "-", "-"] ['a', 'b', 'c', 'd'].fill(3, 2) {|e| e.to_s } # => ["a", "b", "c", "3", "4"] ['a', 'b', 'c', 'd'].fill(4, 2) {|e| e.to_s } # => ["a", "b", "c", "d", "4", "5"]При необходимости заполняет
nil:['a', 'b', 'c', 'd'].fill('-', 5, 2) # => ["a", "b", "c", "d", nil, "-", "-"] ['a', 'b', 'c', 'd'].fill('-', 6, 2) # => ["a", "b", "c", "d", nil, nil, "-", "-"] ['a', 'b', 'c', 'd'].fill(5, 2) {|e| e.to_s } # => ["a", "b", "c", "d", nil, "5", "6"] ['a', 'b', 'c', 'd'].fill(6, 2) {|e| e.to_s } # => ["a", "b", "c", "d", nil, nil, "6", "7"]Ничего не делает, если
countнеположительно:['a', 'b', 'c', 'd'].fill('-', 2, 0) # => ["a", "b", "c", "d"] ['a', 'b', 'c', 'd'].fill('-', 2, -100) # => ["a", "b", "c", "d"] ['a', 'b', 'c', 'd'].fill('-', 6, -100) # => ["a", "b", "c", "d"] ['a', 'b', 'c', 'd'].fill(2, 0) {|e| fail 'Cannot happen' } # => ["a", "b", "c", "d"] ['a', 'b', 'c', 'd'].fill(2, -100) {|e| fail 'Cannot happen' } # => ["a", "b", "c", "d"] ['a', 'b', 'c', 'd'].fill(6, -100) {|e| fail 'Cannot happen' } # => ["a", "b", "c", "d"] -
Если
startотрицательно, отсчет ведется с концаself:['a', 'b', 'c', 'd'].fill('-', -4, 3) # => ["-", "-", "-", "d"] ['a', 'b', 'c', 'd'].fill('-', -3, 3) # => ["a", "-", "-", "-"] ['a', 'b', 'c', 'd'].fill(-4, 3) {|e| e.to_s } # => ["0", "1", "2", "d"] ['a', 'b', 'c', 'd'].fill(-3, 3) {|e| e.to_s } # => ["a", "1", "2", "3"]При необходимости расширяет
self:['a', 'b', 'c', 'd'].fill('-', -2, 3) # => ["a", "b", "-", "-", "-"] ['a', 'b', 'c', 'd'].fill('-', -1, 3) # => ["a", "b", "c", "-", "-", "-"] ['a', 'b', 'c', 'd'].fill(-2, 3) {|e| e.to_s } # => ["a", "b", "2", "3", "4"] ['a', 'b', 'c', 'd'].fill(-1, 3) {|e| e.to_s } # => ["a", "b", "c", "3", "4", "5"]Начинает с начала
self, еслиstartотрицательно и выходит за допустимый диапазон:['a', 'b', 'c', 'd'].fill('-', -5, 2) # => ["-", "-", "c", "d"] ['a', 'b', 'c', 'd'].fill('-', -6, 2) # => ["-", "-", "c", "d"] ['a', 'b', 'c', 'd'].fill(-5, 2) {|e| e.to_s } # => ["0", "1", "c", "d"] ['a', 'b', 'c', 'd'].fill(-6, 2) {|e| e.to_s } # => ["0", "1", "c", "d"]Ничего не делает, если
countнеположительно:['a', 'b', 'c', 'd'].fill('-', -2, 0) # => ["a", "b", "c", "d"] ['a', 'b', 'c', 'd'].fill('-', -2, -1) # => ["a", "b", "c", "d"] ['a', 'b', 'c', 'd'].fill(-2, 0) {|e| fail 'Cannot happen' } # => ["a", "b", "c", "d"] ['a', 'b', 'c', 'd'].fill(-2, -1) {|e| fail 'Cannot happen' } # => ["a", "b", "c", "d"]
Если задан аргумент range, он должен быть объектом Range с числовыми элементами; значения begin и end определяют элементы self для замены:
-
Если
beginиendположительны, они задают первый и последний заменяемые элементы:['a', 'b', 'c', 'd'].fill('-', 1..2) # => ["a", "-", "-", "d"] ['a', 'b', 'c', 'd'].fill(1..2) {|e| e.to_s } # => ["a", "1", "2", "d"]Если
endменьшеbegin, элементы не заменяются:['a', 'b', 'c', 'd'].fill('-', 2..1) # => ["a", "b", "c", "d"] ['a', 'b', 'c', 'd'].fill(2..1) {|e| e.to_s } # => ["a", "b", "c", "d"] -
Если одно из значений отрицательно (или оба отрицательны), отсчет ведется с конца
self:['a', 'b', 'c', 'd'].fill('-', -3..2) # => ["a", "-", "-", "d"] ['a', 'b', 'c', 'd'].fill('-', 1..-2) # => ["a", "-", "-", "d"] ['a', 'b', 'c', 'd'].fill('-', -3..-2) # => ["a", "-", "-", "d"] ['a', 'b', 'c', 'd'].fill(-3..2) {|e| e.to_s } # => ["a", "1", "2", "d"] ['a', 'b', 'c', 'd'].fill(1..-2) {|e| e.to_s } # => ["a", "1", "2", "d"] ['a', 'b', 'c', 'd'].fill(-3..-2) {|e| e.to_s } # => ["a", "1", "2", "d"] -
Если значение
endисключено (см.Range#exclude_end?), последняя замена пропускается:['a', 'b', 'c', 'd'].fill('-', 1...2) # => ["a", "-", "c", "d"] ['a', 'b', 'c', 'd'].fill('-', 1...-2) # => ["a", "-", "c", "d"] ['a', 'b', 'c', 'd'].fill(1...2) {|e| e.to_s } # => ["a", "1", "c", "d"] ['a', 'b', 'c', 'd'].fill(1...-2) {|e| e.to_s } # => ["a", "1", "c", "d"] -
Если диапазон не имеет конца (см. Диапазоны без конца), заменяются элементы до конца
self:['a', 'b', 'c', 'd'].fill('-', 1..) # => ["a", "-", "-", "-"] ['a', 'b', 'c', 'd'].fill(1..) {|e| e.to_s } # => ["a", "1", "2", "3"] -
Если диапазон не имеет начала (см. Диапазоны без начала), заменяются элементы начиная с начала
self:['a', 'b', 'c', 'd'].fill('-', ..2) # => ["-", "-", "-", "d"] ['a', 'b', 'c', 'd'].fill(..2) {|e| e.to_s } # => ["0", "1", "2", "d"]
Связанные методы: см. Методы присваивания.
Если задан блок, вызывает его для каждого элемента self; возвращает новый массив, содержащий те элементы self, для которых блок возвращает истинное значение:
a = [:foo, 'bar', 2, :bam]
a.select {|element| element.to_s.start_with?('b') }
# => ["bar", :bam]
Если блок не задан, возвращает новый Enumerator.
Связанные методы: см. Методы для получения элементов.
Если задан блок, вызывает его для каждого элемента self; удаляет из self те элементы, для которых блок возвращает false или nil.
Если какие-либо элементы были удалены, возвращает self:
a = [:foo, 'bar', 2, :bam]
a.select! {|element| element.to_s.start_with?('b') } # => ["bar", :bam]
Если элементы не удалялись, возвращает nil.
Если блок не задан, возвращает новый Enumerator.
Связанные методы: см. Методы для удаления.
static VALUE
rb_ary_find(int argc, VALUE *argv, VALUE ary)
{
VALUE if_none;
long idx;
RETURN_ENUMERATOR(ary, argc, argv);
if_none = rb_check_arity(argc, 0, 1) ? argv[0] : Qnil;
for (idx = 0; idx < RARRAY_LEN(ary); idx++) {
VALUE elem = RARRAY_AREF(ary, idx);
if (RTEST(rb_yield(elem))) {
return elem;
}
}
if (!NIL_P(if_none)) {
return rb_funcallv(if_none, idCall, 0, 0);
}
return Qnil;
} Возвращает первый элемент, для которого блок возвращает истинное значение.
Если задан блок, вызывает его для последовательно перебираемых элементов массива; возвращает первый элемент, для которого блок возвращает истинное значение:
[1, 3, 5].find {|element| element > 2} # => 3
Если такой элемент не найден, вызывает if_none_proc и возвращает результат его выполнения.
[1, 3, 5].find(proc {-1}) {|element| element > 12} # => -1
Если блок не задан, возвращает Enumerator.
static VALUE
rb_ary_index(int argc, VALUE *argv, VALUE ary)
{
VALUE val;
long i;
if (argc == 0) {
RETURN_ENUMERATOR(ary, 0, 0);
for (i=0; i<RARRAY_LEN(ary); i++) {
if (RTEST(rb_yield(RARRAY_AREF(ary, i)))) {
return LONG2NUM(i);
}
}
return Qnil;
}
rb_check_arity(argc, 0, 1);
val = argv[0];
if (rb_block_given_p())
rb_warn("given block not used");
for (i=0; i<RARRAY_LEN(ary); i++) {
VALUE e = RARRAY_AREF(ary, i);
if (rb_equal(e, val)) {
return LONG2NUM(i);
}
}
return Qnil;
} Возвращает целочисленный индекс элемента, начиная с нуля, или nil.
Если задан только аргумент object, возвращает индекс первого элемента element, для которого выполняется object == element:
a = [:foo, 'bar', 2, 'bar']
a.index('bar') # => 1
Если такой элемент не найден, возвращает nil.
Если задан только блок, вызывает его для каждого последующего элемента; возвращает индекс первого элемента, для которого блок возвращает истинное значение:
a = [:foo, 'bar', 2, 'bar']
a.index {|element| element == 'bar' } # => 1
Если блок ни разу не возвращает истинное значение, возвращает nil.
Если не заданы ни аргумент, ни блок, возвращает новый Enumerator.
Связанные методы: см. Методы для проверки.
# File array.rb, line 129
def first n = unspecified = true
if Primitive.mandatory_only?
Primitive.attr! :leaf
Primitive.cexpr! %q{ ary_first(self) }
else
if unspecified
Primitive.cexpr! %q{ ary_first(self) }
else
Primitive.cexpr! %q{ ary_take_first_or_last_n(self, NUM2LONG(n), ARY_TAKE_FIRST) }
end
end
end Возвращает элементы из self или nil; не изменяет self.
Если аргумент не задан, возвращает первый элемент (если он есть):
a = [:foo, 'bar', 2] a.first # => :foo a # => [:foo, "bar", 2]
Если self пуст, возвращает nil.
[].first # => nil
Если задан неотрицательный целочисленный аргумент count, возвращает первые count элементов (если они имеются) в новом массиве:
a.first(0) # => [] a.first(2) # => [:foo, "bar"] a.first(50) # => [:foo, "bar", 2]
Связанные методы: см. Методы для проверки.
static VALUE
rb_ary_flatten(int argc, VALUE *argv, VALUE ary)
{
int level = -1;
VALUE result;
if (rb_check_arity(argc, 0, 1) && !NIL_P(argv[0])) {
level = NUM2INT(argv[0]);
if (level == 0) return ary_make_shared_copy(ary);
}
result = flatten(ary, level);
if (result == ary) {
result = ary_make_shared_copy(ary);
}
return result;
} Возвращает новый массив, полученный рекурсивным уплощением self на depth уровней рекурсии; depth должен быть объектом, преобразуемым в целое число, или nil. На каждом уровне рекурсии:
-
Каждый элемент, являющийся массивом, «уплощается» (то есть заменяется отдельными элементами этого массива).
-
Каждый элемент, не являющийся массивом, остается без изменений (даже если это объект, у которого есть метод экземпляра
flatten).
Если задан неотрицательный целочисленный аргумент depth, рекурсивное уплощение выполняется на depth уровней:
a = [ 0, [ 1, [2, 3], 4 ], 5, {foo: 0}, Set.new([6, 7]) ]
a # => [0, [1, [2, 3], 4], 5, {:foo=>0}, #<Set: {6, 7}>]
a.flatten(0) # => [0, [1, [2, 3], 4], 5, {:foo=>0}, #<Set: {6, 7}>]
a.flatten(1 ) # => [0, 1, [2, 3], 4, 5, {:foo=>0}, #<Set: {6, 7}>]
a.flatten(1.1) # => [0, 1, [2, 3], 4, 5, {:foo=>0}, #<Set: {6, 7}>]
a.flatten(2) # => [0, 1, 2, 3, 4, 5, {:foo=>0}, #<Set: {6, 7}>]
a.flatten(3) # => [0, 1, 2, 3, 4, 5, {:foo=>0}, #<Set: {6, 7}>]
Если задано nil или отрицательное значение depth, уплощаются все уровни.
a.flatten # => [0, 1, 2, 3, 4, 5, {:foo=>0}, #<Set: {6, 7}>]
a.flatten(-1) # => [0, 1, 2, 3, 4, 5, {:foo=>0}, #<Set: {6, 7}>]
Связанные методы: Array#flatten!; см. также Методы преобразования.
static VALUE
rb_ary_flatten_bang(int argc, VALUE *argv, VALUE ary)
{
int mod = 0, level = -1;
VALUE result, lv;
lv = (rb_check_arity(argc, 0, 1) ? argv[0] : Qnil);
rb_ary_modify_check(ary);
if (!NIL_P(lv)) level = NUM2INT(lv);
if (level == 0) return Qnil;
result = flatten(ary, level);
if (result == ary) {
return Qnil;
}
if (!(mod = ARY_EMBED_P(result))) rb_ary_freeze(result);
rb_ary_replace(ary, result);
if (mod) ARY_SET_EMBED_LEN(result, 0);
return ary;
} Возвращает self в результате рекурсивного уплощения self до depth уровней рекурсии; depth должен быть объектом, преобразуемым в целое число, или nil. На каждом уровне рекурсии:
-
Каждый элемент, являющийся массивом, «уплощается» (то есть заменяется отдельными элементами этого массива).
-
Каждый элемент, не являющийся массивом, остается без изменений (даже если этот элемент — объект с методом экземпляра
flatten).
Возвращает nil, если ни один элемент не был уплощен.
При неотрицательном целочисленном аргументе depth рекурсивно уплощает до depth уровней:
a = [ 0, [ 1, [2, 3], 4 ], 5, {foo: 0}, Set.new([6, 7]) ]
a # => [0, [1, [2, 3], 4], 5, {:foo=>0}, #<Set: {6, 7}>]
a.dup.flatten!(1) # => [0, 1, [2, 3], 4, 5, {:foo=>0}, #<Set: {6, 7}>]
a.dup.flatten!(1.1) # => [0, 1, [2, 3], 4, 5, {:foo=>0}, #<Set: {6, 7}>]
a.dup.flatten!(2) # => [0, 1, 2, 3, 4, 5, {:foo=>0}, #<Set: {6, 7}>]
a.dup.flatten!(3) # => [0, 1, 2, 3, 4, 5, {:foo=>0}, #<Set: {6, 7}>]
При аргументе nil или отрицательном аргументе depth уплощает все уровни:
a.dup.flatten! # => [0, 1, 2, 3, 4, 5, {:foo=>0}, #<Set: {6, 7}>]
a.dup.flatten!(-1) # => [0, 1, 2, 3, 4, 5, {:foo=>0}, #<Set: {6, 7}>]
Связанный метод: Array#flatten; см. также Методы присваивания.
VALUE
rb_ary_freeze(VALUE ary)
{
RUBY_ASSERT(RB_TYPE_P(ary, T_ARRAY));
if (OBJ_FROZEN(ary)) return ary;
if (!ARY_EMBED_P(ary) && !ARY_SHARED_P(ary) && !ARY_SHARED_ROOT_P(ary)) {
ary_shrink_capa(ary);
}
return rb_obj_freeze(ary);
} Замораживает self (если он еще не заморожен); возвращает self:
a = [] a.frozen? # => false a.freeze a.frozen? # => true
В дальнейшем self нельзя изменять; при попытке изменения возникает исключение FrozenError.
Связанный метод: Kernel#frozen?.
static VALUE
rb_ary_hash(VALUE ary)
{
RBIMPL_ASSERT_OR_ASSUME(ary);
return ary_hash_values(RARRAY_LEN(ary), RARRAY_CONST_PTR(ary), ary);
} Возвращает целочисленное хеш-значение для self.
Два массива с одинаковым содержимым будут иметь одинаковое хеш-значение (и будут сравниваться с помощью eql?):
['a', 'b'].hash == ['a', 'b'].hash # => true ['a', 'b'].hash == ['a', 'c'].hash # => false ['a', 'b'].hash == ['a'].hash # => false
VALUE
rb_ary_includes(VALUE ary, VALUE item)
{
long i;
VALUE e;
for (i=0; i<RARRAY_LEN(ary); i++) {
e = RARRAY_AREF(ary, i);
if (rb_equal(e, item)) {
return Qtrue;
}
}
return Qfalse;
} Возвращает, существует ли в self элемент element, для которого выполняется условие object == element:
[0, 1, 2].include?(2) # => true [0, 1, 2].include?(2.0) # => true [0, 1, 2].include?(2.1) # => false
Связанный раздел: см. Методы запросов.
Возвращает индекс указанного элемента, отсчитываемый от нуля, или nil.
Если задан только аргумент object, возвращает индекс первого элемента element, для которого object == element:
a = [:foo, 'bar', 2, 'bar']
a.index('bar') # => 1
Возвращает nil, если такой элемент не найден.
Если задан только блок, вызывает его для каждого элемента по очереди; возвращает индекс первого элемента, для которого блок возвращает истинное значение:
a = [:foo, 'bar', 2, 'bar']
a.index {|element| element == 'bar' } # => 1
Возвращает nil, если блок ни разу не вернул истинное значение.
Если не задан ни аргумент, ни блок, возвращает новый Enumerator.
Связанный раздел: см. Методы запросов.
VALUE
rb_ary_replace(VALUE copy, VALUE orig)
{
rb_ary_modify_check(copy);
orig = to_ary(orig);
if (copy == orig) return copy;
rb_ary_reset(copy);
/* orig has enough space to embed the contents of orig. */
if (RARRAY_LEN(orig) <= ary_embed_capa(copy)) {
RUBY_ASSERT(ARY_EMBED_P(copy));
ary_memcpy(copy, 0, RARRAY_LEN(orig), RARRAY_CONST_PTR(orig));
ARY_SET_EMBED_LEN(copy, RARRAY_LEN(orig));
}
/* orig is embedded but copy does not have enough space to embed the
* contents of orig. */
else if (ARY_EMBED_P(orig)) {
long len = ARY_EMBED_LEN(orig);
VALUE *ptr = ary_heap_alloc_buffer(len);
FL_UNSET_EMBED(copy);
ARY_SET_PTR(copy, ptr);
ARY_SET_LEN(copy, len);
ARY_SET_CAPA(copy, len);
// No allocation and exception expected that could leave `copy` in a
// bad state from the edits above.
ary_memcpy(copy, 0, len, RARRAY_CONST_PTR(orig));
}
/* Otherwise, orig is on heap and copy does not have enough space to embed
* the contents of orig. */
else {
VALUE shared_root = ary_make_shared(orig);
FL_UNSET_EMBED(copy);
ARY_SET_PTR(copy, ARY_HEAP_PTR(orig));
ARY_SET_LEN(copy, ARY_HEAP_LEN(orig));
rb_ary_set_shared(copy, shared_root);
RUBY_ASSERT(RB_OBJ_SHAREABLE_P(copy) ? RB_OBJ_SHAREABLE_P(shared_root) : 1);
}
ary_verify(copy);
return copy;
} Заменяет элементы self элементами other_array, который должен быть объектом, преобразуемым в массив; возвращает self:
a = ['a', 'b', 'c'] # => ["a", "b", "c"] a.replace(['d', 'e']) # => ["d", "e"]
Связанный раздел: см. Методы присваивания.
static VALUE
rb_ary_insert(int argc, VALUE *argv, VALUE ary)
{
long pos;
rb_check_arity(argc, 1, UNLIMITED_ARGUMENTS);
rb_ary_modify_check(ary);
pos = NUM2LONG(argv[0]);
if (argc == 1) return ary;
if (pos == -1) {
pos = RARRAY_LEN(ary);
}
else if (pos < 0) {
long minpos = -RARRAY_LEN(ary) - 1;
if (pos < minpos) {
rb_raise(rb_eIndexError, "index %ld too small for array; minimum: %ld",
pos, minpos);
}
pos++;
}
rb_ary_splice(ary, pos, 0, argv + 1, argc - 1);
return ary;
} Вставляет заданные objects в self в качестве элементов; возвращает self.
Если index неотрицателен, вставляет objects перед элементом со смещением index:
a = ['a', 'b', 'c'] # => ["a", "b", "c"] a.insert(1, :x, :y, :z) # => ["a", :x, :y, :z, "b", "c"]
Расширяет массив, если index выходит за его границы (index >= self.size):
a = ['a', 'b', 'c'] # => ["a", "b", "c"] a.insert(5, :x, :y, :z) # => ["a", "b", "c", nil, nil, :x, :y, :z]
Если index отрицателен, вставляет objects после элемента со смещением index + self.size:
a = ['a', 'b', 'c'] # => ["a", "b", "c"] a.insert(-2, :x, :y, :z) # => ["a", "b", :x, :y, :z, "c"]
Если objects не задан, ничего не делает:
a = ['a', 'b', 'c'] # => ["a", "b", "c"] a.insert(1) # => ["a", "b", "c"] a.insert(50) # => ["a", "b", "c"] a.insert(-50) # => ["a", "b", "c"]
Вызывает исключение IndexError, если заданы objects, а index отрицателен и выходит за допустимый диапазон.
Связанный раздел: см. Методы присваивания.
static VALUE
rb_ary_inspect(VALUE ary)
{
if (RARRAY_LEN(ary) == 0) return rb_usascii_str_new2("[]");
return rb_exec_recursive(inspect_ary, ary, 0);
} Возвращает новую строку, сформированную вызовом метода inspect для каждого элемента массива:
a = [:foo, 'bar', 2] a.inspect # => "[:foo, \"bar\", 2]"
Связанный раздел: см. Методы преобразования.
static VALUE
rb_ary_intersect_p(VALUE ary1, VALUE ary2)
{
VALUE hash, v, result, shorter, longer;
st_data_t vv;
long i;
ary2 = to_ary(ary2);
if (RARRAY_LEN(ary1) == 0 || RARRAY_LEN(ary2) == 0) return Qfalse;
if (RARRAY_LEN(ary1) <= SMALL_ARRAY_LEN && RARRAY_LEN(ary2) <= SMALL_ARRAY_LEN) {
for (i=0; i<RARRAY_LEN(ary1); i++) {
v = RARRAY_AREF(ary1, i);
if (rb_ary_includes_by_eql(ary2, v)) return Qtrue;
}
return Qfalse;
}
shorter = ary1;
longer = ary2;
if (RARRAY_LEN(ary1) > RARRAY_LEN(ary2)) {
longer = ary1;
shorter = ary2;
}
hash = ary_make_hash(shorter);
result = Qfalse;
for (i=0; i<RARRAY_LEN(longer); i++) {
v = RARRAY_AREF(longer, i);
vv = (st_data_t)v;
if (rb_hash_stlike_lookup(hash, vv, 0)) {
result = Qtrue;
break;
}
}
return result;
} Возвращает, содержит ли other_array хотя бы один элемент, который eql? некоторому элементу self:
[1, 2, 3].intersect?([3, 4, 5]) # => true [1, 2, 3].intersect?([4, 5, 6]) # => false
Каждый элемент должен корректно реализовывать метод hash.
Связанный раздел: см. Методы запросов.
static VALUE
rb_ary_intersection_multi(int argc, VALUE *argv, VALUE ary)
{
VALUE result = rb_ary_dup(ary);
int i;
for (i = 0; i < argc; i++) {
result = rb_ary_and(result, argv[i]);
}
return result;
} Возвращает новый массив, содержащий каждый элемент self, который eql? хотя бы одному элементу каждого из заданных other_arrays; дубликаты исключаются:
[0, 0, 1, 1, 2, 3].intersection([0, 1, 2], [0, 1, 3]) # => [0, 1]
Каждый элемент должен корректно реализовывать метод hash.
Порядок элементов из self сохраняется:
[0, 1, 2].intersection([2, 1, 0]) # => [0, 1, 2]
Если аргументы не заданы, возвращает копию self.
Связанный раздел: см. Методы объединения.
static VALUE
rb_ary_join_m(int argc, VALUE *argv, VALUE ary)
{
VALUE sep;
if (rb_check_arity(argc, 0, 1) == 0 || NIL_P(sep = argv[0])) {
sep = rb_output_fs;
if (!NIL_P(sep)) {
rb_category_warn(RB_WARN_CATEGORY_DEPRECATED, "$, is set to non-nil value");
}
}
return rb_ary_join(ary, sep);
} Возвращает новую строку, полученную объединением преобразованных элементов self; для каждого элемента element:
-
Выполняет рекурсивное преобразование с помощью
element.join(separator), еслиelementявляетсяkind_of?(Array). -
В противном случае преобразует с помощью
element.to_s.
Если аргумент не задан, объединяет элементы, используя разделитель полей вывода $,:
a = [:foo, 'bar', 2] $, # => nil a.join # => "foobar2"
Если задан строковый аргумент separator, объединяет элементы, используя его в качестве разделителя:
a = [:foo, 'bar', 2]
a.join("\n") # => "foo\nbar\n2"
Рекурсивно объединяет вложенные массивы:
a = [:foo, [:bar, [:baz, :bat]]] a.join # => "foobarbazbat"
Связанный раздел: см. Методы преобразования.
static VALUE
rb_ary_keep_if(VALUE ary)
{
RETURN_SIZED_ENUMERATOR(ary, 0, 0, ary_enum_length);
rb_ary_select_bang(ary);
return ary;
} Если задан блок, вызывает его для каждого элемента self; удаляет элемент из self, если блок не возвращает истинное значение:
a = [:foo, 'bar', 2, :bam]
a.keep_if {|element| element.to_s.start_with?('b') } # => ["bar", :bam]
Если блок не задан, возвращает новый Enumerator.
Связанный раздел: см. Методы удаления.
# File array.rb, line 166
def last n = unspecified = true
if Primitive.mandatory_only?
Primitive.attr! :leaf
Primitive.cexpr! %q{ ary_last(self) }
else
if unspecified
Primitive.cexpr! %q{ ary_last(self) }
else
Primitive.cexpr! %q{ ary_take_first_or_last_n(self, NUM2LONG(n), ARY_TAKE_LAST) }
end
end
end Возвращает элементы из self или nil; self не изменяется.
Если аргумент не задан, возвращает последний элемент или nil, если self пуст:
a = [:foo, 'bar', 2] a.last # => 2 a # => [:foo, "bar", 2] [].last # => nil
Если задан неотрицательный целочисленный аргумент count, возвращает новый массив, содержащий последние count элементов self, если они доступны:
a = [:foo, 'bar', 2] a.last(2) # => ["bar", 2] a.last(50) # => [:foo, "bar", 2] a.last(0) # => [] [].last(3) # => []
Связанный раздел: см. Методы извлечения.
static VALUE
rb_ary_length(VALUE ary)
{
long len = RARRAY_LEN(ary);
return LONG2NUM(len);
} Возвращает количество элементов в self:
[0, 1, 2].length # => 3 [].length # => 0
Связанный раздел: см. Методы запросов.
Если задан блок, вызывает его для каждого элемента self; возвращает новый массив, элементы которого являются значениями, возвращенными блоком:
a = [:foo, 'bar', 2]
a1 = a.map {|element| element.class }
a1 # => [Symbol, String, Integer]
Если блок не задан, возвращает новый Enumerator.
Связанный метод: collect!; см. также Методы преобразования.
Если задан блок, вызывает его для каждого элемента self и заменяет элемент значением, возвращенным блоком; возвращает self:
a = [:foo, 'bar', 2]
a.map! { |element| element.class } # => [Symbol, String, Integer]
Если блок не задан, возвращает новый Enumerator.
Связанный метод: collect; см. также Методы преобразования.
static VALUE
rb_ary_max(int argc, VALUE *argv, VALUE ary)
{
VALUE result = Qundef, v;
VALUE num;
long i;
if (rb_check_arity(argc, 0, 1) && !NIL_P(num = argv[0]))
return rb_nmin_run(ary, num, 0, 1, 1);
const long n = RARRAY_LEN(ary);
if (rb_block_given_p()) {
for (i = 0; i < RARRAY_LEN(ary); i++) {
v = RARRAY_AREF(ary, i);
if (UNDEF_P(result) || rb_cmpint(rb_yield_values(2, v, result), v, result) > 0) {
result = v;
}
}
}
else if (n > 0) {
result = RARRAY_AREF(ary, 0);
if (n > 1) {
if (FIXNUM_P(result) && CMP_OPTIMIZABLE(INTEGER)) {
return ary_max_opt_fixnum(ary, 1, result);
}
else if (STRING_P(result) && CMP_OPTIMIZABLE(STRING)) {
return ary_max_opt_string(ary, 1, result);
}
else if (RB_FLOAT_TYPE_P(result) && CMP_OPTIMIZABLE(FLOAT)) {
return ary_max_opt_float(ary, 1, result);
}
else {
return ary_max_generic(ary, 1, result);
}
}
}
if (UNDEF_P(result)) return Qnil;
return result;
} Возвращает одно из следующего:
-
Элемент с максимальным значением из
self. -
Новый массив элементов с максимальными значениями из
self.
Не изменяет self.
Если блок не задан, каждый элемент в self должен отвечать на метод <=> числовым значением.
Если не заданы ни аргумент, ни блок, возвращает элемент self с максимальным значением согласно методу <=>:
[1, 0, 3, 2].max # => 3
Если задан неотрицательный числовой аргумент count, но блок не задан, возвращает новый массив не более чем из count элементов в порядке убывания согласно методу <=>:
[1, 0, 3, 2].max(3) # => [3, 2, 1] [1, 0, 3, 2].max(3.0) # => [3, 2, 1] [1, 0, 3, 2].max(9) # => [3, 2, 1, 0] [1, 0, 3, 2].max(0) # => []
Если задан блок, он должен возвращать числовое значение.
Если задан блок, но не задан аргумент, вызывает блок self.size - 1 раз для сравнения элементов; возвращает элемент с максимальным значением согласно блоку:
['0', '', '000', '00'].max {|a, b| a.size <=> b.size }
# => "000"
Если задан неотрицательный числовой аргумент count и блок, возвращает новый массив не более чем из count элементов в порядке убывания согласно блоку:
['0', '', '000', '00'].max(2) {|a, b| a.size <=> b.size }
# => ["000", "00"]
Связанный раздел: см. Методы извлечения.
static VALUE
rb_ary_min(int argc, VALUE *argv, VALUE ary)
{
VALUE result = Qundef, v;
VALUE num;
long i;
if (rb_check_arity(argc, 0, 1) && !NIL_P(num = argv[0]))
return rb_nmin_run(ary, num, 0, 0, 1);
const long n = RARRAY_LEN(ary);
if (rb_block_given_p()) {
for (i = 0; i < RARRAY_LEN(ary); i++) {
v = RARRAY_AREF(ary, i);
if (UNDEF_P(result) || rb_cmpint(rb_yield_values(2, v, result), v, result) < 0) {
result = v;
}
}
}
else if (n > 0) {
result = RARRAY_AREF(ary, 0);
if (n > 1) {
if (FIXNUM_P(result) && CMP_OPTIMIZABLE(INTEGER)) {
return ary_min_opt_fixnum(ary, 1, result);
}
else if (STRING_P(result) && CMP_OPTIMIZABLE(STRING)) {
return ary_min_opt_string(ary, 1, result);
}
else if (RB_FLOAT_TYPE_P(result) && CMP_OPTIMIZABLE(FLOAT)) {
return ary_min_opt_float(ary, 1, result);
}
else {
return ary_min_generic(ary, 1, result);
}
}
}
if (UNDEF_P(result)) return Qnil;
return result;
} Возвращает одно из следующего:
-
Элемент с минимальным значением из
self. -
Новый массив элементов с минимальными значениями из
self.
Не изменяет self.
Если блок не задан, каждый элемент в self должен отвечать на метод <=> числовым значением.
Если не заданы ни аргумент, ни блок, возвращает элемент self с минимальным значением согласно методу <=>:
[1, 0, 3, 2].min # => 0
Если задан неотрицательный числовой аргумент count, но блок не задан, возвращает новый массив не более чем из count элементов в порядке возрастания согласно методу <=>:
[1, 0, 3, 2].min(3) # => [0, 1, 2] [1, 0, 3, 2].min(3.0) # => [0, 1, 2] [1, 0, 3, 2].min(9) # => [0, 1, 2, 3] [1, 0, 3, 2].min(0) # => []
Если задан блок, он должен возвращать числовое значение.
Если задан блок, но не задан аргумент, вызывает блок self.size - 1 раз для сравнения элементов; возвращает элемент с минимальным значением согласно блоку:
['0', '', '000', '00'].min {|a, b| a.size <=> b.size }
# => ""
Если задан неотрицательный числовой аргумент count и блок, возвращает новый массив не более чем из count элементов в порядке возрастания согласно блоку:
['0', '', '000', '00'].min(2) {|a, b| a.size <=> b.size }
# => ["", "0"]
Связанный раздел: см. Методы извлечения.
static VALUE
rb_ary_minmax(VALUE ary)
{
if (rb_block_given_p()) {
return rb_call_super(0, NULL);
}
return rb_assoc_new(rb_ary_min(0, 0, ary), rb_ary_max(0, 0, ary));
} Возвращает массив из двух элементов, содержащий элементы с минимальным и максимальным значениями из self; не изменяет self.
Если блок не задан, минимальное и максимальное значения определяются с помощью метода <=>:
[1, 0, 3, 2].minmax # => [0, 3]
Если задан блок, он должен возвращать числовое значение; блок вызывается self.size - 1 раз для сравнения элементов; возвращает элементы с минимальным и максимальным значениями согласно блоку:
['0', '', '000', '00'].minmax {|a, b| a.size <=> b.size }
# => ["", "000"]
Связанный раздел: см. Методы извлечения.
static VALUE
rb_ary_none_p(int argc, VALUE *argv, VALUE ary)
{
long i, len = RARRAY_LEN(ary);
rb_check_arity(argc, 0, 1);
if (!len) return Qtrue;
if (argc) {
if (rb_block_given_p()) {
rb_warn("given block not used");
}
for (i = 0; i < RARRAY_LEN(ary); ++i) {
if (RTEST(rb_funcall(argv[0], idEqq, 1, RARRAY_AREF(ary, i)))) return Qfalse;
}
}
else if (!rb_block_given_p()) {
for (i = 0; i < len; ++i) {
if (RTEST(RARRAY_AREF(ary, i))) return Qfalse;
}
}
else {
for (i = 0; i < RARRAY_LEN(ary); ++i) {
if (RTEST(rb_yield(RARRAY_AREF(ary, i)))) return Qfalse;
}
}
return Qtrue;
} Возвращает true, если ни один элемент self не удовлетворяет заданному условию, и false в противном случае.
Если не заданы ни блок, ни аргумент, возвращает true, если в self нет истинных элементов, и false в противном случае:
[nil, false].none? # => true [nil, 0, false].none? # => false [].none? # => true
Если задан аргумент object, возвращает false, если для любого элемента element выполняется object === element; в противном случае возвращает true:
['food', 'drink'].none?(/bar/) # => true ['food', 'drink'].none?(/foo/) # => false [].none?(/foo/) # => true [0, 1, 2].none?(3) # => true [0, 1, 2].none?(1) # => false
Если задан блок, вызывает его для каждого элемента в self; возвращает true, если блок ни разу не вернул истинное значение, и false в противном случае:
[0, 1, 2].none? {|element| element > 3 } # => true
[0, 1, 2].none? {|element| element > 1 } # => false
Связанный раздел: см. Методы запросов.
static VALUE
rb_ary_one_p(int argc, VALUE *argv, VALUE ary)
{
long i, len = RARRAY_LEN(ary);
VALUE result = Qfalse;
rb_check_arity(argc, 0, 1);
if (!len) return Qfalse;
if (argc) {
if (rb_block_given_p()) {
rb_warn("given block not used");
}
for (i = 0; i < RARRAY_LEN(ary); ++i) {
if (RTEST(rb_funcall(argv[0], idEqq, 1, RARRAY_AREF(ary, i)))) {
if (result) return Qfalse;
result = Qtrue;
}
}
}
else if (!rb_block_given_p()) {
for (i = 0; i < len; ++i) {
if (RTEST(RARRAY_AREF(ary, i))) {
if (result) return Qfalse;
result = Qtrue;
}
}
}
else {
for (i = 0; i < RARRAY_LEN(ary); ++i) {
if (RTEST(rb_yield(RARRAY_AREF(ary, i)))) {
if (result) return Qfalse;
result = Qtrue;
}
}
}
return result;
} Возвращает true, если заданному условию удовлетворяет ровно один элемент self.
Если не заданы ни блок, ни аргумент, возвращает true, если в self ровно один истинный элемент, и false в противном случае:
[nil, 0].one? # => true [0, 0].one? # => false [nil, nil].one? # => false [].one? # => false
Если задан блок, вызывает его для каждого элемента в self; возвращает true, если блок возвращает истинное значение ровно для одного элемента, и false в противном случае:
[0, 1, 2].one? {|element| element > 0 } # => false
[0, 1, 2].one? {|element| element > 1 } # => true
[0, 1, 2].one? {|element| element > 2 } # => false
Если задан аргумент object, возвращает true, если ровно для одного элемента element выполняется object === element; в противном случае возвращает false:
[0, 1, 2].one?(0) # => true [0, 0, 1].one?(0) # => false [1, 1, 2].one?(0) # => false ['food', 'drink'].one?(/bar/) # => false ['food', 'drink'].one?(/foo/) # => true [].one?(/foo/) # => false
Связанный раздел: см. Методы запросов.
# File pack.rb, line 7 def pack(fmt, buffer: nil) Primitive.pack_pack(fmt, buffer) end
Форматирует каждый элемент self в двоичную строку; возвращает эту строку. См. Упакованные данные.
static VALUE
rb_ary_permutation(int argc, VALUE *argv, VALUE ary)
{
long r, n, i;
n = RARRAY_LEN(ary); /* Array length */
RETURN_SIZED_ENUMERATOR(ary, argc, argv, rb_ary_permutation_size); /* Return enumerator if no block */
r = n;
if (rb_check_arity(argc, 0, 1) && !NIL_P(argv[0]))
r = NUM2LONG(argv[0]); /* Permutation size from argument */
if (r < 0 || n < r) {
/* no permutations: yield nothing */
}
else if (r == 0) { /* exactly one permutation: the zero-length array */
rb_yield(rb_ary_new2(0));
}
else if (r == 1) { /* this is a special, easy case */
for (i = 0; i < RARRAY_LEN(ary); i++) {
rb_yield(rb_ary_new3(1, RARRAY_AREF(ary, i)));
}
}
else { /* this is the general case */
volatile VALUE t0;
long *p = ALLOCV_N(long, t0, r+roomof(n, sizeof(long)));
char *used = (char*)(p + r);
VALUE ary0 = ary_make_shared_copy(ary); /* private defensive copy of ary */
RBASIC_CLEAR_CLASS(ary0);
MEMZERO(used, char, n); /* initialize array */
permute0(n, r, p, used, ary0); /* compute and yield permutations */
ALLOCV_END(t0);
RBASIC_SET_CLASS_RAW(ary0, rb_cArray);
}
return ary;
} Перебирает перестановки элементов self; порядок перестановок не определен.
Если задан блок и положительный целочисленный аргумент count находится в допустимом диапазоне (0 < count <= self.size), вызывает блок для каждой перестановки self размера count; возвращает self:
a = [0, 1, 2]
perms = []
a.permutation(1) {|perm| perms.push(perm) }
perms # => [[0], [1], [2]]
perms = []
a.permutation(2) {|perm| perms.push(perm) }
perms # => [[0, 1], [0, 2], [1, 0], [1, 2], [2, 0], [2, 1]]
perms = []
a.permutation(3) {|perm| perms.push(perm) }
perms # => [[0, 1, 2], [0, 2, 1], [1, 0, 2], [1, 2, 0], [2, 0, 1], [2, 1, 0]]
Если count равно нулю, вызывает блок один раз с новым пустым массивом:
perms = []
a.permutation(0) {|perm| perms.push(perm) }
perms # => [[]]
Если count выходит за допустимый диапазон (отрицательно или больше self.size), блок не вызывается:
a.permutation(-1) {|permutation| fail 'Cannot happen' }
a.permutation(4) {|permutation| fail 'Cannot happen' }
Если блок не задан, возвращает новый Enumerator.
Связанный раздел: Методы итерации.
static VALUE
rb_ary_pop_m(int argc, VALUE *argv, VALUE ary)
{
VALUE result;
if (argc == 0) {
return rb_ary_pop(ary);
}
rb_ary_modify_check(ary);
result = ary_take_first_or_last(argc, argv, ary, ARY_TAKE_LAST);
ARY_INCREASE_LEN(ary, -RARRAY_LEN(result));
ary_verify(ary);
return result;
} Удаляет и возвращает последние элементы self.
Если аргумент не задан, удаляет и возвращает последний элемент, если он есть; в противном случае возвращает nil:
a = [:foo, 'bar', 2] a.pop # => 2 a # => [:foo, "bar"] [].pop # => nil
Если задан неотрицательный целочисленный аргумент count, возвращает новый массив, содержащий последние count элементов self, если они доступны:
a = [:foo, 'bar', 2] a.pop(2) # => ["bar", 2] a # => [:foo] a = [:foo, 'bar', 2] a.pop(50) # => [:foo, "bar", 2] a # => []
Связанный метод: Array#push; см. также Методы удаления.
Добавляет заданные objects в начало self:
a = [:foo, 'bar', 2] a.unshift(:bam, :bat) # => [:bam, :bat, :foo, "bar", 2]
Связанный метод: Array#shift; см. также Методы присваивания.
static VALUE
rb_ary_product(int argc, VALUE *argv, VALUE ary)
{
int n = argc+1; /* How many arrays we're operating on */
volatile VALUE t0 = rb_ary_hidden_new(n);
volatile VALUE t1 = Qundef;
VALUE *arrays = RARRAY_PTR(t0); /* The arrays we're computing the product of */
int *counters = ALLOCV_N(int, t1, n); /* The current position in each one */
VALUE result = Qnil; /* The array we'll be returning, when no block given */
long i,j;
long resultlen = 1;
RBASIC_CLEAR_CLASS(t0);
/* initialize the arrays of arrays */
ARY_SET_LEN(t0, n);
arrays[0] = ary;
for (i = 1; i < n; i++) arrays[i] = Qnil;
for (i = 1; i < n; i++) arrays[i] = to_ary(argv[i-1]);
/* initialize the counters for the arrays */
for (i = 0; i < n; i++) counters[i] = 0;
/* Otherwise, allocate and fill in an array of results */
if (rb_block_given_p()) {
/* Make defensive copies of arrays; exit if any is empty */
for (i = 0; i < n; i++) {
if (RARRAY_LEN(arrays[i]) == 0) goto done;
arrays[i] = ary_make_shared_copy(arrays[i]);
}
}
else {
/* Compute the length of the result array; return [] if any is empty */
for (i = 0; i < n; i++) {
long k = RARRAY_LEN(arrays[i]);
if (k == 0) {
result = rb_ary_new2(0);
goto done;
}
if (MUL_OVERFLOW_LONG_P(resultlen, k))
rb_raise(rb_eRangeError, "too big to product");
resultlen *= k;
}
result = rb_ary_new2(resultlen);
}
for (;;) {
int m;
/* fill in one subarray */
VALUE subarray = rb_ary_new2(n);
for (j = 0; j < n; j++) {
rb_ary_push(subarray, rb_ary_entry(arrays[j], counters[j]));
}
/* put it on the result array */
if (NIL_P(result)) {
FL_SET(t0, RARRAY_SHARED_ROOT_FLAG);
rb_yield(subarray);
if (!FL_TEST(t0, RARRAY_SHARED_ROOT_FLAG)) {
rb_raise(rb_eRuntimeError, "product reentered");
}
else {
FL_UNSET(t0, RARRAY_SHARED_ROOT_FLAG);
}
}
else {
rb_ary_push(result, subarray);
}
/*
* Increment the last counter. If it overflows, reset to 0
* and increment the one before it.
*/
m = n-1;
counters[m]++;
while (counters[m] == RARRAY_LEN(arrays[m])) {
counters[m] = 0;
/* If the first counter overflows, we are done */
if (--m < 0) goto done;
counters[m]++;
}
}
done:
ALLOCV_END(t1);
return NIL_P(result) ? ary : result;
} Вычисляет все комбинации элементов из всех массивов, включая как self, так и other_arrays:
-
Количество комбинаций равно произведению размеров всех массивов, включая как
self, так иother_arrays. -
Порядок возвращаемых комбинаций не определён.
Если блок не задан, возвращает комбинации в виде массива массивов:
p = [0, 1].product([2, 3]) # => [[0, 2], [0, 3], [1, 2], [1, 3]] p.size # => 4 p = [0, 1].product([2, 3], [4, 5]) # => [[0, 2, 4], [0, 2, 5], [0, 3, 4], [0, 3, 5], [1, 2, 4], [1, 2, 5], [1, 3, 4], [1, 3,... p.size # => 8
Если self или любой аргумент пуст, возвращает пустой массив:
[].product([2, 3], [4, 5]) # => [] [0, 1].product([2, 3], []) # => []
Если аргументы не заданы, возвращает массив массивов из одного элемента, каждый из которых содержит элемент из self:
a.product # => [[0], [1], [2]]
Если блок задан, вызывает блок для каждой комбинации; возвращает self:
p = []
[0, 1].product([2, 3]) {|combination| p.push(combination) }
p # => [[0, 2], [0, 3], [1, 2], [1, 3]]
Если self или любой аргумент пуст, блок не вызывается:
[].product([2, 3], [4, 5]) {|combination| fail 'Cannot happen' }
# => []
[0, 1].product([2, 3], []) {|combination| fail 'Cannot happen' }
# => [0, 1]
Если аргументы не заданы, вызывает блок для каждого элемента из self, передавая его в виде массива из одного элемента:
p = []
[0, 1].product {|combination| p.push(combination) }
p # => [[0], [1]]
См. также: методы комбинирования.
static VALUE
rb_ary_push_m(int argc, VALUE *argv, VALUE ary)
{
return rb_ary_cat(ary, argv, argc);
} Добавляет каждый аргумент из objects в self; возвращает self:
a = [:foo, 'bar', 2] # => [:foo, "bar", 2] a.push(:baz, :bat) # => [:foo, "bar", 2, :baz, :bat]
Добавляет каждый аргумент как отдельный элемент, даже если он является другим массивом:
a = [:foo, 'bar', 2] # => [:foo, "bar", 2] a.push([:baz, :bat], [:bam, :bad]) # => [:foo, "bar", 2, [:baz, :bat], [:bam, :bad]]
См. также: методы присваивания.
VALUE
rb_ary_rassoc(VALUE ary, VALUE value)
{
long i;
VALUE v;
for (i = 0; i < RARRAY_LEN(ary); ++i) {
v = rb_check_array_type(RARRAY_AREF(ary, i));
if (RB_TYPE_P(v, T_ARRAY) &&
RARRAY_LEN(v) > 1 &&
rb_equal(RARRAY_AREF(v, 1), value))
return v;
}
return Qnil;
} Возвращает первый элемент ele в self, для которого ele является массивом и ele[1] == object:
a = [{foo: 0}, [2, 4], [4, 5, 6], [4, 5]]
a.rassoc(4) # => [2, 4]
a.rassoc(5) # => [4, 5, 6]
Возвращает nil, если такой элемент не найден.
Связанный метод: Array#assoc; см. также методы получения данных.
static VALUE
rb_ary_reject(VALUE ary)
{
VALUE rejected_ary;
RETURN_SIZED_ENUMERATOR(ary, 0, 0, ary_enum_length);
rejected_ary = rb_ary_new();
ary_reject(ary, rejected_ary);
return rejected_ary;
} Если блок задан, возвращает новый массив, содержащий все элементы из self, для которых блок возвращает false или nil:
a = [:foo, 'bar', 2, 'bat']
a1 = a.reject {|element| element.to_s.start_with?('b') }
a1 # => [:foo, 2]
Если блок не задан, возвращает новый Enumerator.
См. также: методы получения данных.
static VALUE
rb_ary_reject_bang(VALUE ary)
{
RETURN_SIZED_ENUMERATOR(ary, 0, 0, ary_enum_length);
rb_ary_modify(ary);
return ary_reject_bang(ary);
} Если блок задан, вызывает его для каждого элемента self; удаляет каждый элемент, для которого блок возвращает истинное значение.
Возвращает self, если были удалены какие-либо элементы:
a = [:foo, 'bar', 2, 'bat']
a.reject! {|element| element.to_s.start_with?('b') } # => [:foo, 2]
Возвращает nil, если ни один элемент не был удалён.
Если блок не задан, возвращает новый Enumerator.
См. также: методы удаления.
static VALUE
rb_ary_repeated_combination(VALUE ary, VALUE num)
{
long n, i, len;
n = NUM2LONG(num); /* Combination size from argument */
RETURN_SIZED_ENUMERATOR(ary, 1, &num, rb_ary_repeated_combination_size); /* Return enumerator if no block */
len = RARRAY_LEN(ary);
if (n < 0) {
/* yield nothing */
}
else if (n == 0) {
rb_yield(rb_ary_new2(0));
}
else if (n == 1) {
for (i = 0; i < RARRAY_LEN(ary); i++) {
rb_yield(rb_ary_new3(1, RARRAY_AREF(ary, i)));
}
}
else if (len == 0) {
/* yield nothing */
}
else {
volatile VALUE t0;
long *p = ALLOCV_N(long, t0, n);
VALUE ary0 = ary_make_shared_copy(ary); /* private defensive copy of ary */
RBASIC_CLEAR_CLASS(ary0);
rcombinate0(len, n, p, n, ary0); /* compute and yield repeated combinations */
ALLOCV_END(t0);
RBASIC_SET_CLASS_RAW(ary0, rb_cArray);
}
return ary;
} Если блок задан, вызывает его для каждой повторяющейся комбинации длины size из элементов self; каждая комбинация представляет собой массив; возвращает self. Порядок комбинаций не определён.
Если задан положительный целочисленный аргумент size, вызывает блок для каждой повторяющейся комбинации элементов self длины size. Количество комбинаций равно (size+1)(size+2)/2.
Примеры:
-
sizeравно 1:c = [] [0, 1, 2].repeated_combination(1) {|combination| c.push(combination) } c # => [[0], [1], [2]] -
sizeравно 2:c = [] [0, 1, 2].repeated_combination(2) {|combination| c.push(combination) } c # => [[0, 0], [0, 1], [0, 2], [1, 1], [1, 2], [2, 2]]
Если size равно нулю, вызывает блок один раз с пустым массивом.
Если size отрицательно, блок не вызывается:
[0, 1, 2].repeated_combination(-1) {|combination| fail 'Cannot happen' }
Если блок не задан, возвращает новый Enumerator.
См. также: методы комбинирования.
static VALUE
rb_ary_repeated_permutation(VALUE ary, VALUE num)
{
long r, n, i;
n = RARRAY_LEN(ary); /* Array length */
RETURN_SIZED_ENUMERATOR(ary, 1, &num, rb_ary_repeated_permutation_size); /* Return Enumerator if no block */
r = NUM2LONG(num); /* Permutation size from argument */
if (r < 0) {
/* no permutations: yield nothing */
}
else if (r == 0) { /* exactly one permutation: the zero-length array */
rb_yield(rb_ary_new2(0));
}
else if (r == 1) { /* this is a special, easy case */
for (i = 0; i < RARRAY_LEN(ary); i++) {
rb_yield(rb_ary_new3(1, RARRAY_AREF(ary, i)));
}
}
else { /* this is the general case */
volatile VALUE t0;
long *p = ALLOCV_N(long, t0, r);
VALUE ary0 = ary_make_shared_copy(ary); /* private defensive copy of ary */
RBASIC_CLEAR_CLASS(ary0);
rpermute0(n, r, p, ary0); /* compute and yield repeated permutations */
ALLOCV_END(t0);
RBASIC_SET_CLASS_RAW(ary0, rb_cArray);
}
return ary;
} Если блок задан, вызывает его для каждой повторяющейся перестановки длины size из элементов self; каждая перестановка представляет собой массив; возвращает self. Порядок перестановок не определён.
Если задан положительный целочисленный аргумент size, вызывает блок для каждой повторяющейся перестановки элементов self длины size. Количество перестановок равно self.size**size.
Примеры:
-
sizeравно 1:p = [] [0, 1, 2].repeated_permutation(1) {|permutation| p.push(permutation) } p # => [[0], [1], [2]] -
sizeравно 2:p = [] [0, 1, 2].repeated_permutation(2) {|permutation| p.push(permutation) } p # => [[0, 0], [0, 1], [0, 2], [1, 0], [1, 1], [1, 2], [2, 0], [2, 1], [2, 2]]
Если size равно нулю, вызывает блок один раз с пустым массивом.
Если size отрицательно, блок не вызывается:
[0, 1, 2].repeated_permutation(-1) {|permutation| fail 'Cannot happen' }
Если блок не задан, возвращает новый Enumerator.
См. также: методы комбинирования.
Заменяет элементы self элементами other_array, который должен быть объектом, преобразуемым в массив; возвращает self:
a = ['a', 'b', 'c'] # => ["a", "b", "c"] a.replace(['d', 'e']) # => ["d", "e"]
См. также: методы присваивания.
static VALUE
rb_ary_reverse_m(VALUE ary)
{
long len = RARRAY_LEN(ary);
VALUE dup = rb_ary_new2(len);
if (len > 0) {
const VALUE *p1 = RARRAY_CONST_PTR(ary);
VALUE *p2 = (VALUE *)RARRAY_CONST_PTR(dup) + len - 1;
do *p2-- = *p1++; while (--len > 0);
}
ARY_SET_LEN(dup, RARRAY_LEN(ary));
return dup;
} Возвращает новый массив, содержащий элементы self в обратном порядке:
[0, 1, 2].reverse # => [2, 1, 0]
См. также: методы комбинирования.
static VALUE
rb_ary_reverse_bang(VALUE ary)
{
return rb_ary_reverse(ary);
} Меняет порядок элементов self на обратный; возвращает self:
a = [0, 1, 2] a.reverse! # => [2, 1, 0] a # => [2, 1, 0]
См. также: методы присваивания.
static VALUE
rb_ary_reverse_each(VALUE ary)
{
long len;
RETURN_SIZED_ENUMERATOR(ary, 0, 0, ary_enum_length);
len = RARRAY_LEN(ary);
while (len--) {
long nlen;
rb_yield(RARRAY_AREF(ary, len));
nlen = RARRAY_LEN(ary);
if (nlen < len) {
len = nlen;
}
}
return ary;
} Если блок задан, перебирает элементы self в обратном направлении, передавая каждый элемент блоку в обратном порядке; возвращает self:
a = []
[0, 1, 2].reverse_each {|element| a.push(element) }
a # => [2, 1, 0]
Допускает изменение массива во время итерации:
a = ['a', 'b', 'c']
a.reverse_each {|element| a.clear if element.start_with?('b') }
a # => []
Если блок не задан, возвращает новый Enumerator.
См. также: методы итерации.
static VALUE
rb_ary_rfind(int argc, VALUE *argv, VALUE ary)
{
VALUE if_none;
long len, idx;
RETURN_ENUMERATOR(ary, argc, argv);
if_none = rb_check_arity(argc, 0, 1) ? argv[0] : Qnil;
idx = RARRAY_LEN(ary);
while (idx--) {
VALUE elem = RARRAY_AREF(ary, idx);
if (RTEST(rb_yield(elem))) {
return elem;
}
len = RARRAY_LEN(ary);
idx = (idx >= len) ? len : idx;
}
if (!NIL_P(if_none)) {
return rb_funcallv(if_none, idCall, 0, 0);
}
return Qnil;
} Возвращает последний элемент, для которого блок возвращает истинное значение.
Если блок задан, вызывает его для последовательных элементов массива в обратном порядке; возвращает первый элемент, для которого блок возвращает истинное значение:
[1, 2, 3, 4, 5, 6].rfind {|element| element < 5} # => 4
Если такой элемент не найден, вызывает if_none_proc и возвращает значение, возвращённое этим вызовом.
[1, 2, 3, 4].rfind(proc {0}) {|element| element < -2} # => 0
Если блок не задан, возвращает Enumerator.
static VALUE
rb_ary_rindex(int argc, VALUE *argv, VALUE ary)
{
VALUE val;
long i = RARRAY_LEN(ary), len;
if (argc == 0) {
RETURN_ENUMERATOR(ary, 0, 0);
while (i--) {
if (RTEST(rb_yield(RARRAY_AREF(ary, i))))
return LONG2NUM(i);
if (i > (len = RARRAY_LEN(ary))) {
i = len;
}
}
return Qnil;
}
rb_check_arity(argc, 0, 1);
val = argv[0];
if (rb_block_given_p())
rb_warn("given block not used");
while (i--) {
VALUE e = RARRAY_AREF(ary, i);
if (rb_equal(e, val)) {
return LONG2NUM(i);
}
if (i > RARRAY_LEN(ary)) {
break;
}
}
return Qnil;
} Возвращает индекс последнего элемента, для которого выполняется object == element.
Если задан аргумент object, возвращает индекс последнего найденного элемента, удовлетворяющего этому условию:
a = [:foo, 'bar', 2, 'bar']
a.rindex('bar') # => 3
Возвращает nil, если такой объект не найден.
Если блок задан, вызывает его для каждого последующего элемента; возвращает индекс последнего элемента, для которого блок возвращает истинное значение:
a = [:foo, 'bar', 2, 'bar']
a.rindex {|element| element == 'bar' } # => 3
Возвращает nil, если блок ни разу не возвращает истинное значение.
Если не задан ни аргумент, ни блок, возвращает новый Enumerator.
См. также: методы проверки.
static VALUE
rb_ary_rotate_m(int argc, VALUE *argv, VALUE ary)
{
VALUE rotated;
const VALUE *ptr;
long len;
long cnt = (rb_check_arity(argc, 0, 1) ? NUM2LONG(argv[0]) : 1);
len = RARRAY_LEN(ary);
rotated = rb_ary_new2(len);
if (len > 0) {
cnt = rotate_count(cnt, len);
ptr = RARRAY_CONST_PTR(ary);
len -= cnt;
ary_memcpy(rotated, 0, len, ptr + cnt);
ary_memcpy(rotated, len, cnt, ptr);
}
ARY_SET_LEN(rotated, RARRAY_LEN(ary));
return rotated;
} Возвращает новый массив, полученный из self циклическим переносом элементов с одного конца на другой.
При неотрицательном числовом значении count переносит элементы из начала в конец:
[0, 1, 2, 3].rotate(2) # => [2, 3, 0, 1] [0, 1, 2, 3].rotate(2.1) # => [2, 3, 0, 1]
Если count велико, использует count % array.size в качестве количества:
[0, 1, 2, 3].rotate(22) # => [2, 3, 0, 1]
При значении count, равном нулю, элементы не перемещаются:
[0, 1, 2, 3].rotate(0) # => [0, 1, 2, 3]
При отрицательном числовом значении count переносит элементы в противоположном направлении, с конца в начало:
[0, 1, 2, 3].rotate(-1) # => [3, 0, 1, 2]
Если count мало (далеко от нуля), использует count % array.size в качестве количества:
[0, 1, 2, 3].rotate(-21) # => [3, 0, 1, 2]
См. также: методы получения данных.
static VALUE
rb_ary_rotate_bang(int argc, VALUE *argv, VALUE ary)
{
long n = (rb_check_arity(argc, 0, 1) ? NUM2LONG(argv[0]) : 1);
rb_ary_rotate(ary, n);
return ary;
} Циклически перемещает элементы self с одного конца на другой, изменяя массив на месте; возвращает self.
При неотрицательном числовом значении count переносит count элементов из начала в конец:
[0, 1, 2, 3].rotate!(2) # => [2, 3, 0, 1] [0, 1, 2, 3].rotate!(2.1) # => [2, 3, 0, 1]
Если count велико, использует count % array.size в качестве количества:
[0, 1, 2, 3].rotate!(21) # => [1, 2, 3, 0]
Если count равно нулю, элементы не перемещаются:
[0, 1, 2, 3].rotate!(0) # => [0, 1, 2, 3]
При отрицательном числовом значении count переносит элементы в противоположном направлении, с конца в начало:
[0, 1, 2, 3].rotate!(-1) # => [3, 0, 1, 2]
Если count мало (далеко от нуля), использует count % array.size в качестве количества:
[0, 1, 2, 3].rotate!(-21) # => [3, 0, 1, 2]
См. также: методы присваивания.
# File array.rb, line 95
def sample(n = (ary = false), random: Random)
if Primitive.mandatory_only?
# Primitive.cexpr! %{ rb_ary_sample(self, rb_cRandom, Qfalse, Qfalse) }
Primitive.ary_sample0
else
# Primitive.cexpr! %{ rb_ary_sample(self, random, n, ary) }
Primitive.ary_sample(random, n, ary)
end
end Возвращает случайные элементы из self, выбранные объектом, заданным ключевым аргументом random.
Если аргумент count не задан, возвращает один случайный элемент из self:
a = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] a.sample # => 3 a.sample # => 8
Возвращает nil, если self пуст:
[].sample # => nil
Если задан неотрицательный числовой аргумент count, возвращает новый массив, содержащий count случайных элементов из self:
a.sample(3) # => [8, 9, 2] a.sample(6) # => [9, 6, 0, 3, 1, 4]
Порядок элементов результирующего массива не связан с порядком элементов в self.
Если self пуст, возвращает новый пустой массив:
[].sample(4) # => []
В self могут присутствовать повторяющиеся элементы:
a = [1, 1, 1, 2, 2, 3] a.sample(a.size) # => [1, 1, 3, 2, 1, 2]
Возвращает не более a.size элементов (поскольку новые повторы не добавляются):
a.sample(50) # => [6, 4, 1, 8, 5, 9, 0, 2, 3, 7]
Объект, заданный ключевым аргументом random, используется в качестве генератора случайных чисел:
a = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] a.sample(random: Random.new(1)) # => 6 a.sample(4, random: Random.new(1)) # => [6, 10, 9, 2]
См. также: методы получения данных.
static VALUE
rb_ary_select(VALUE ary)
{
VALUE result;
long i;
RETURN_SIZED_ENUMERATOR(ary, 0, 0, ary_enum_length);
result = rb_ary_new2(RARRAY_LEN(ary));
for (i = 0; i < RARRAY_LEN(ary); i++) {
if (RTEST(rb_yield(RARRAY_AREF(ary, i)))) {
rb_ary_push(result, rb_ary_elt(ary, i));
}
}
return result;
} Если блок задан, вызывает его для каждого элемента self; возвращает новый массив, содержащий те элементы self, для которых блок возвращает истинное значение:
a = [:foo, 'bar', 2, :bam]
a.select {|element| element.to_s.start_with?('b') }
# => ["bar", :bam]
Если блок не задан, возвращает новый Enumerator.
См. также: методы получения данных.
static VALUE
rb_ary_select_bang(VALUE ary)
{
struct select_bang_arg args;
RETURN_SIZED_ENUMERATOR(ary, 0, 0, ary_enum_length);
rb_ary_modify(ary);
args.ary = ary;
args.len[0] = args.len[1] = 0;
return rb_ensure(select_bang_i, (VALUE)&args, select_bang_ensure, (VALUE)&args);
} Если блок задан, вызывает его для каждого элемента self; удаляет из self те элементы, для которых блок возвращает false или nil.
Возвращает self, если были удалены какие-либо элементы:
a = [:foo, 'bar', 2, :bam]
a.select! {|element| element.to_s.start_with?('b') } # => ["bar", :bam]
Возвращает nil, если ни один элемент не был удалён.
Если блок не задан, возвращает новый Enumerator.
См. также: методы удаления.
# File lib/shellwords.rb, line 251 def shelljoin Shellwords.join(self) end
Формирует строку командной строки из списка аргументов array, объединяя все элементы, экранированные для оболочки Bourne, пробелами.
Подробности см. в описании Shellwords.shelljoin.
static VALUE
rb_ary_shift_m(int argc, VALUE *argv, VALUE ary)
{
VALUE result;
long n;
if (argc == 0) {
return rb_ary_shift(ary);
}
rb_ary_modify_check(ary);
result = ary_take_first_or_last(argc, argv, ary, ARY_TAKE_FIRST);
n = RARRAY_LEN(result);
rb_ary_behead(ary,n);
return result;
} Удаляет начальные элементы из self и возвращает их.
Если аргумент не задан, удаляет и возвращает один элемент, если он доступен, или nil в противном случае:
a = [0, 1, 2, 3] a.shift # => 0 a # => [1, 2, 3] [].shift # => nil
Если задан неотрицательный числовой аргумент count, удаляет и возвращает первые count элементов:
a = [0, 1, 2, 3] a.shift(2) # => [0, 1] a # => [2, 3] a.shift(1.1) # => [2] a # => [3] a.shift(0) # => [] a # => [3]
Если count велико, удаляет и возвращает все элементы:
a = [0, 1, 2, 3] a.shift(50) # => [0, 1, 2, 3] a # => []
Если self пуст, возвращает новый пустой массив.
См. также: методы удаления.
# File array.rb, line 45 def shuffle(random: Random) Primitive.rb_ary_shuffle(random) end
Возвращает новый массив, содержащий все элементы self в случайном порядке, выбранном объектом, заданным ключевым аргументом random:
a = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] a.shuffle # => [0, 8, 1, 9, 6, 3, 4, 7, 2, 5] a.shuffle # => [8, 9, 0, 5, 1, 2, 6, 4, 7, 3]
Повторяющиеся элементы также включаются:
a = [0, 1, 0, 1, 0, 1, 0, 1, 0, 1] a.shuffle # => [1, 0, 1, 1, 0, 0, 1, 0, 0, 1] a.shuffle # => [1, 1, 0, 0, 0, 1, 1, 0, 0, 1]
Объект, заданный ключевым аргументом random, используется в качестве генератора случайных чисел.
См. также: методы получения данных.
# File array.rb, line 22 def shuffle!(random: Random) Primitive.rb_ary_shuffle_bang(random) end
Перемешивает все элементы self в случайном порядке, выбранном объектом, заданным ключевым аргументом random. Возвращает self:
a = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] a.shuffle! # => [5, 3, 8, 7, 6, 1, 9, 4, 2, 0] a.shuffle! # => [9, 4, 0, 6, 2, 8, 1, 5, 3, 7]
Повторяющиеся элементы также включаются:
a = [0, 1, 0, 1, 0, 1, 0, 1, 0, 1] a.shuffle! # => [1, 0, 0, 1, 1, 0, 1, 0, 0, 1] a.shuffle! # => [0, 1, 0, 1, 1, 0, 1, 0, 1, 0]
Объект, заданный ключевым аргументом random, используется в качестве генератора случайных чисел.
См. также: методы присваивания.
Возвращает количество элементов в self:
[0, 1, 2].length # => 3 [].length # => 0
См. также: методы проверки.
Возвращает элементы из self; не изменяет self.
Кратко:
a = [:foo, 'bar', 2] # Single argument index: returns one element. a[0] # => :foo # Zero-based index. a[-1] # => 2 # Negative index counts backwards from end. # Arguments start and length: returns an array. a[1, 2] # => ["bar", 2] a[-2, 2] # => ["bar", 2] # Negative start counts backwards from end. # Single argument range: returns an array. a[0..1] # => [:foo, "bar"] a[0..-2] # => [:foo, "bar"] # Negative range-begin counts backwards from end. a[-2..2] # => ["bar", 2] # Negative range-end counts backwards from end.
Если задан один целочисленный аргумент index, возвращает элемент со смещением index:
a = [:foo, 'bar', 2] a[0] # => :foo a[2] # => 2 a # => [:foo, "bar", 2]
Если index отрицательно, отсчёт ведётся с конца self:
a = [:foo, 'bar', 2] a[-1] # => 2 a[-2] # => "bar"
Если index выходит за допустимый диапазон, возвращает nil.
Если заданы два аргумента типа Integer — start и length, — возвращает новый массив размером length, содержащий последовательные элементы, начиная со смещения start:
a = [:foo, 'bar', 2] a[0, 2] # => [:foo, "bar"] a[1, 2] # => ["bar", 2]
Если start + length больше self.length, возвращает все элементы от смещения start до конца:
a = [:foo, 'bar', 2] a[0, 4] # => [:foo, "bar", 2] a[1, 3] # => ["bar", 2] a[2, 2] # => [2]
Если start == self.size и length >= 0, возвращает новый пустой массив.
Если length отрицательно, возвращает nil.
Если задан один аргумент типа Range — range, — обрабатывает range.min так же, как start выше, а range.size так же, как length выше:
a = [:foo, 'bar', 2] a[0..1] # => [:foo, "bar"] a[1..2] # => ["bar", 2]
Особый случай: если range.start == a.size, возвращает новый пустой массив.
Если range.end отрицательно, вычисляет конечный индекс, считая от конца:
a = [:foo, 'bar', 2] a[0..-1] # => [:foo, "bar", 2] a[0..-2] # => [:foo, "bar"] a[0..-3] # => [:foo]
Если range.start отрицательно, вычисляет начальный индекс, считая от конца:
a = [:foo, 'bar', 2] a[-1..2] # => [2] a[-2..2] # => ["bar", 2] a[-3..2] # => [:foo, "bar", 2]
Если range.start больше размера массива, возвращает nil.
a = [:foo, 'bar', 2] a[4..1] # => nil a[4..0] # => nil a[4..-1] # => nil
Если задан один аргумент типа Enumerator::ArithmeticSequence — aseq, — возвращает массив элементов, соответствующих индексам, созданным этой последовательностью.
a = ['--', 'data1', '--', 'data2', '--', 'data3'] a[(1..).step(2)] # => ["data1", "data2", "data3"]
В отличие от извлечения с помощью диапазона, если начало или конец арифметической последовательности выходит за размер массива, вызывает RangeError.
a = ['--', 'data1', '--', 'data2', '--', 'data3'] a[(1..11).step(2)] # RangeError (((1..11).step(2)) out of range) a[(7..).step(2)] # RangeError (((7..).step(2)) out of range)
Если задан один аргумент, тип которого не входит в перечисленные, пытается преобразовать его в Integer и вызывает исключение, если это невозможно:
a = [:foo, 'bar', 2] # Raises TypeError (no implicit conversion of Symbol into Integer): a[:foo]
См. также: методы получения данных.
static VALUE
rb_ary_slice_bang(int argc, VALUE *argv, VALUE ary)
{
VALUE arg1;
long pos, len;
rb_ary_modify_check(ary);
rb_check_arity(argc, 1, 2);
arg1 = argv[0];
if (argc == 2) {
pos = NUM2LONG(argv[0]);
len = NUM2LONG(argv[1]);
return ary_slice_bang_by_rb_ary_splice(ary, pos, len);
}
if (!FIXNUM_P(arg1)) {
switch (rb_range_beg_len(arg1, &pos, &len, RARRAY_LEN(ary), 0)) {
case Qtrue:
/* valid range */
return ary_slice_bang_by_rb_ary_splice(ary, pos, len);
case Qnil:
/* invalid range */
return Qnil;
default:
/* not a range */
break;
}
}
return rb_ary_delete_at(ary, NUM2LONG(arg1));
} Удаляет и возвращает элементы из self.
Если указан числовой аргумент index, удаляет и возвращает элемент со смещением index:
a = ['a', 'b', 'c', 'd'] a.slice!(2) # => "c" a # => ["a", "b", "d"] a.slice!(2.1) # => "d" a # => ["a", "b"]
Если index отрицателен, отсчёт ведётся с конца self:
a = ['a', 'b', 'c', 'd'] a.slice!(-2) # => "c" a # => ["a", "b", "d"]
Если index выходит за допустимый диапазон, возвращает nil.
Если указаны числовые аргументы start и length, удаляет length элементов из self, начиная с отсчитываемого с нуля смещения start; возвращает удалённые объекты в новом массиве:
a = ['a', 'b', 'c', 'd'] a.slice!(1, 2) # => ["b", "c"] a # => ["a", "d"] a.slice!(0.1, 1.1) # => ["a"] a # => ["d"]
Если start отрицателен, отсчёт ведётся с конца self:
a = ['a', 'b', 'c', 'd'] a.slice!(-2, 1) # => ["c"] a # => ["a", "b", "d"]
Если start выходит за допустимый диапазон, возвращает nil:
a = ['a', 'b', 'c', 'd'] a.slice!(5, 1) # => nil a.slice!(-5, 1) # => nil
Если start + length превышает размер массива, удаляет и возвращает все элементы от смещения start до конца:
a = ['a', 'b', 'c', 'd'] a.slice!(2, 50) # => ["c", "d"] a # => ["a", "b"]
Если start == a.size и length неотрицательно, возвращает новый пустой массив.
Если length отрицателен, возвращает nil.
Если указан аргумент Range range, обрабатывает range.min как start (как описано выше), а range.size как length (как описано выше):
a = ['a', 'b', 'c', 'd'] a.slice!(1..2) # => ["b", "c"] a # => ["a", "d"]
Если range.start == a.size, возвращает новый пустой массив:
a = ['a', 'b', 'c', 'd'] a.slice!(4..5) # => []
Если range.start больше размера массива, возвращает nil:
a = ['a', 'b', 'c', 'd'] a.slice!(5..6) # => nil
Если range.start отрицателен, вычисляет начальный индекс, отсчитывая его с конца self:
a = ['a', 'b', 'c', 'd'] a.slice!(-2..2) # => ["c"]
Если range.end отрицателен, вычисляет конечный индекс, отсчитывая его с конца self:
a = ['a', 'b', 'c', 'd'] a.slice!(0..-2) # => ["a", "b", "c"]
Связанные методы: см. Методы удаления.
VALUE
rb_ary_sort(VALUE ary)
{
ary = rb_ary_dup(ary);
rb_ary_sort_bang(ary);
return ary;
} Возвращает новый массив, содержащий отсортированные элементы self.
Если блок не указан, сравнивает элементы с помощью оператора <=> (см. Object#<=>):
[0, 2, 3, 1].sort # => [0, 1, 2, 3]
Если блок указан, вызывает его для каждой комбинации пар элементов из self; для каждой пары a и b блок должен возвращать числовое значение:
-
Отрицательное, если
bдолжен следовать заa. -
Ноль, если
aиbэквивалентны. -
Положительное, если
aдолжен следовать заb.
Пример:
a = [3, 2, 0, 1]
a.sort {|a, b| a <=> b } # => [0, 1, 2, 3]
a.sort {|a, b| b <=> a } # => [3, 2, 1, 0]
Если блок возвращает ноль, порядок элементов a и b не определён и может быть нестабильным.
Пример идиомы для сортировки более сложной структуры см. в Numeric#nonzero?.
Связанные методы: см. Методы извлечения.
VALUE
rb_ary_sort_bang(VALUE ary)
{
rb_ary_modify(ary);
RUBY_ASSERT(!ARY_SHARED_P(ary));
if (RARRAY_LEN(ary) > 1) {
VALUE tmp = ary_make_substitution(ary); /* only ary refers tmp */
struct ary_sort_data data;
long len = RARRAY_LEN(ary);
RBASIC_CLEAR_CLASS(tmp);
data.ary = tmp;
data.receiver = ary;
RARRAY_PTR_USE(tmp, ptr, {
ruby_qsort(ptr, len, sizeof(VALUE),
rb_block_given_p()?sort_1:sort_2, &data);
}); /* WB: no new reference */
rb_ary_modify(ary);
if (ARY_EMBED_P(tmp)) {
if (ARY_SHARED_P(ary)) { /* ary might be destructively operated in the given block */
rb_ary_unshare(ary);
FL_SET_EMBED(ary);
}
if (ARY_EMBED_LEN(tmp) > ARY_CAPA(ary)) {
ary_resize_capa(ary, ARY_EMBED_LEN(tmp));
}
ary_memcpy(ary, 0, ARY_EMBED_LEN(tmp), ARY_EMBED_PTR(tmp));
ARY_SET_LEN(ary, ARY_EMBED_LEN(tmp));
}
else {
if (!ARY_EMBED_P(ary) && ARY_HEAP_PTR(ary) == ARY_HEAP_PTR(tmp)) {
FL_UNSET_SHARED(ary);
ARY_SET_CAPA(ary, RARRAY_LEN(tmp));
}
else {
RUBY_ASSERT(!ARY_SHARED_P(tmp));
if (ARY_EMBED_P(ary)) {
FL_UNSET_EMBED(ary);
}
else if (ARY_SHARED_P(ary)) {
/* ary might be destructively operated in the given block */
rb_ary_unshare(ary);
}
else {
ary_heap_free(ary);
}
ARY_SET_PTR(ary, ARY_HEAP_PTR(tmp));
ARY_SET_HEAP_LEN(ary, len);
ARY_SET_CAPA(ary, ARY_HEAP_LEN(tmp));
}
/* tmp was lost ownership for the ptr */
FL_SET_EMBED(tmp);
ARY_SET_EMBED_LEN(tmp, 0);
OBJ_FREEZE(tmp);
}
/* tmp will be GC'ed. */
RBASIC_SET_CLASS_RAW(tmp, rb_cArray); /* rb_cArray must be marked */
}
ary_verify(ary);
return ary;
} Как Array#sort, но возвращает self, элементы которого отсортированы на месте.
Связанные методы: см. Методы присваивания.
static VALUE
rb_ary_sort_by_bang(VALUE ary)
{
VALUE sorted;
RETURN_SIZED_ENUMERATOR(ary, 0, 0, ary_enum_length);
rb_ary_modify(ary);
if (RARRAY_LEN(ary) > 1) {
sorted = rb_block_call(ary, rb_intern("sort_by"), 0, 0, sort_by_i, 0);
rb_ary_replace(ary, sorted);
}
return ary;
} Если блок указан, сортирует элементы self на месте; возвращает self.
Вызывает блок для каждого элемента по порядку; сортирует элементы на основе значений, возвращённых блоком:
a = ['aaaa', 'bbb', 'cc', 'd']
a.sort_by! {|element| element.size }
a # => ["d", "cc", "bbb", "aaaa"]
Порядок элементов с одинаковыми значениями, возвращёнными блоком, не определён и может быть нестабильным.
Если блок не указан, возвращает новый Enumerator.
Связанные методы: см. Методы присваивания.
static VALUE
rb_ary_sum(int argc, VALUE *argv, VALUE ary)
{
VALUE e, v, r;
long i, n;
int block_given;
v = (rb_check_arity(argc, 0, 1) ? argv[0] : LONG2FIX(0));
block_given = rb_block_given_p();
if (RARRAY_LEN(ary) == 0)
return v;
n = 0;
r = Qundef;
if (!FIXNUM_P(v) && !RB_BIGNUM_TYPE_P(v) && !RB_TYPE_P(v, T_RATIONAL)) {
i = 0;
goto init_is_a_value;
}
for (i = 0; i < RARRAY_LEN(ary); i++) {
e = RARRAY_AREF(ary, i);
if (block_given)
e = rb_yield(e);
if (FIXNUM_P(e)) {
n += FIX2LONG(e); /* should not overflow long type */
if (!FIXABLE(n)) {
v = rb_big_plus(LONG2NUM(n), v);
n = 0;
}
}
else if (RB_BIGNUM_TYPE_P(e))
v = rb_big_plus(e, v);
else if (RB_TYPE_P(e, T_RATIONAL)) {
if (UNDEF_P(r))
r = e;
else
r = rb_rational_plus(r, e);
}
else
goto not_exact;
}
v = finish_exact_sum(n, r, v, argc!=0);
return v;
not_exact:
v = finish_exact_sum(n, r, v, i!=0);
if (RB_FLOAT_TYPE_P(e)) {
/*
* Kahan-Babuska balancing compensated summation algorithm
* See https://link.springer.com/article/10.1007/s00607-005-0139-x
*/
double f, c;
double x, t;
f = NUM2DBL(v);
c = 0.0;
goto has_float_value;
for (; i < RARRAY_LEN(ary); i++) {
e = RARRAY_AREF(ary, i);
if (block_given)
e = rb_yield(e);
if (RB_FLOAT_TYPE_P(e))
has_float_value:
x = RFLOAT_VALUE(e);
else if (FIXNUM_P(e))
x = FIX2LONG(e);
else if (RB_BIGNUM_TYPE_P(e))
x = rb_big2dbl(e);
else if (RB_TYPE_P(e, T_RATIONAL))
x = rb_num2dbl(e);
else
goto not_float;
if (isnan(f)) continue;
if (isnan(x)) {
f = x;
continue;
}
if (isinf(x)) {
if (isinf(f) && signbit(x) != signbit(f))
f = NAN;
else
f = x;
continue;
}
if (isinf(f)) continue;
t = f + x;
if (fabs(f) >= fabs(x))
c += ((f - t) + x);
else
c += ((x - t) + f);
f = t;
}
f += c;
return DBL2NUM(f);
not_float:
v = DBL2NUM(f);
}
goto has_some_value;
init_is_a_value:
for (; i < RARRAY_LEN(ary); i++) {
e = RARRAY_AREF(ary, i);
if (block_given)
e = rb_yield(e);
has_some_value:
v = rb_funcall(v, idPLUS, 1, e);
}
return v;
} Если блок не указан, возвращает сумму init и всех элементов self; для массива array и значения init это эквивалентно:
sum = init
array.each {|element| sum += element }
sum
Например, [e0, e1, e2].sum возвращает init + e0 + e1 + e2.
Примеры:
[0, 1, 2, 3].sum # => 6
[0, 1, 2, 3].sum(100) # => 106
['abc', 'def', 'ghi'].sum('jkl') # => "jklabcdefghi"
[[:foo, :bar], ['foo', 'bar']].sum([2, 3])
# => [2, 3, :foo, :bar, "foo", "bar"]
Значение init и элементы не обязательно должны быть числами, но все они должны быть совместимы с +:
# Raises TypeError: Array can't be coerced into Integer. [[:foo, :bar], ['foo', 'bar']].sum(2)
Если блок указан, вызывает его для каждого элемента self; возвращаемое блоком значение (вместо самого элемента) используется в качестве слагаемого:
['zero', 1, :two].sum('Coerced and concatenated: ') {|element| element.to_s }
# => "Coerced and concatenated: zero1two"
Примечания:
-
Для массива строк или массива массивов методы
Array#joinиArray#flattenмогут работать быстрее, чемArray#sum. -
Метод
Array#sumможет не учитывать переопределение методов «+», таких какInteger#+.
static VALUE
rb_ary_take(VALUE obj, VALUE n)
{
long len = NUM2LONG(n);
if (len < 0) {
rb_raise(rb_eArgError, "attempt to take negative size");
}
return rb_ary_subseq(obj, 0, len);
} Возвращает новый массив, содержащий первые count элементов self (если они есть); count должен быть неотрицательным числом; self не изменяется:
a = ['a', 'b', 'c', 'd'] a.take(2) # => ["a", "b"] a.take(2.1) # => ["a", "b"] a.take(50) # => ["a", "b", "c", "d"] a.take(0) # => []
Связанные методы: см. Методы извлечения.
static VALUE
rb_ary_take_while(VALUE ary)
{
long i;
RETURN_ENUMERATOR(ary, 0, 0);
for (i = 0; i < RARRAY_LEN(ary); i++) {
if (!RTEST(rb_yield(RARRAY_AREF(ary, i)))) break;
}
return rb_ary_take(ary, LONG2FIX(i));
} Если блок указан, вызывает его для каждого последующего элемента self; прекращает итерацию, если блок возвращает false или nil; возвращает новый массив, содержащий элементы, для которых блок вернул истинное значение:
a = [0, 1, 2, 3, 4, 5]
a.take_while {|element| element < 3 } # => [0, 1, 2]
a.take_while {|element| true } # => [0, 1, 2, 3, 4, 5]
a.take_while {|element| false } # => []
Если блок не указан, возвращает новый Enumerator.
Не изменяет self.
Связанные методы: см. Методы извлечения.
static VALUE
rb_ary_to_a(VALUE ary)
{
if (rb_obj_class(ary) != rb_cArray) {
VALUE dup = rb_ary_new2(RARRAY_LEN(ary));
rb_ary_replace(dup, ary);
return dup;
}
return ary;
} Если self является экземпляром Array, возвращает self.
В противном случае возвращает новый массив, содержащий элементы self:
class MyArray < Array; end my_a = MyArray.new(['foo', 'bar', 'two']) a = my_a.to_a a # => ["foo", "bar", "two"] a.class # => Array # Not MyArray.
Связанные методы: см. Методы преобразования.
static VALUE
rb_ary_to_ary_m(VALUE ary)
{
return ary;
} Возвращает self.
static VALUE
rb_ary_to_h(VALUE ary)
{
long i;
VALUE hash = rb_hash_new_with_size(RARRAY_LEN(ary));
int block_given = rb_block_given_p();
for (i=0; i<RARRAY_LEN(ary); i++) {
const VALUE e = rb_ary_elt(ary, i);
const VALUE elt = block_given ? rb_yield_force_blockarg(e) : e;
const VALUE key_value_pair = rb_check_array_type(elt);
if (NIL_P(key_value_pair)) {
rb_raise(rb_eTypeError, "wrong element type %"PRIsVALUE" at %ld (expected array)",
rb_obj_class(elt), i);
}
if (RARRAY_LEN(key_value_pair) != 2) {
rb_raise(rb_eArgError, "wrong array length at %ld (expected 2, was %ld)",
i, RARRAY_LEN(key_value_pair));
}
rb_hash_aset(hash, RARRAY_AREF(key_value_pair, 0), RARRAY_AREF(key_value_pair, 1));
}
return hash;
} Возвращает новый хеш, созданный из self.
Если блок не указан, каждый элемент self должен быть подмассивом из двух элементов; каждый такой подмассив становится парой ключ-значение в новом хеше:
a = [['foo', 'zero'], ['bar', 'one'], ['baz', 'two']]
a.to_h # => {"foo"=>"zero", "bar"=>"one", "baz"=>"two"}
[].to_h # => {}
Если блок указан, он должен возвращать массив из двух элементов; блок вызывается для каждого элемента self, а каждый возвращённый массив становится парой ключ-значение в результирующем хеше:
a = ['foo', :bar, 1, [2, 3], {baz: 4}]
a.to_h {|element| [element, element.class] }
# => {"foo"=>String, :bar=>Symbol, 1=>Integer, [2, 3]=>Array, {:baz=>4}=>Hash}
Связанные методы: см. Методы преобразования.
Возвращает новую строку, полученную вызовом метода inspect для каждого элемента массива:
a = [:foo, 'bar', 2] a.inspect # => "[:foo, \"bar\", 2]"
Связанные методы: см. Методы преобразования.
static VALUE
rb_ary_transpose(VALUE ary)
{
long elen = -1, alen, i, j;
VALUE tmp, result = 0;
alen = RARRAY_LEN(ary);
if (alen == 0) return rb_ary_dup(ary);
for (i=0; i<alen; i++) {
tmp = to_ary(rb_ary_elt(ary, i));
if (elen < 0) { /* first element */
elen = RARRAY_LEN(tmp);
result = rb_ary_new2(elen);
for (j=0; j<elen; j++) {
rb_ary_store(result, j, rb_ary_new2(alen));
}
}
else if (elen != RARRAY_LEN(tmp)) {
rb_raise(rb_eIndexError, "element size differs (%ld should be %ld)",
RARRAY_LEN(tmp), elen);
}
for (j=0; j<elen; j++) {
rb_ary_store(rb_ary_elt(result, j), i, rb_ary_elt(tmp, j));
}
}
return result;
} Возвращает новый массив, представляющий self как транспонированная матрица:
a = [[:a0, :a1], [:b0, :b1], [:c0, :c1]] a.transpose # => [[:a0, :b0, :c0], [:a1, :b1, :c1]]
Все элементы self должны иметь одинаковый размер.
Связанные методы: см. Методы преобразования.
static VALUE
rb_ary_union_multi(int argc, VALUE *argv, VALUE ary)
{
int i;
long sum;
VALUE hash;
sum = RARRAY_LEN(ary);
for (i = 0; i < argc; i++) {
argv[i] = to_ary(argv[i]);
sum += RARRAY_LEN(argv[i]);
}
if (sum <= SMALL_ARRAY_LEN) {
VALUE ary_union = rb_ary_new();
rb_ary_union(ary_union, ary);
for (i = 0; i < argc; i++) rb_ary_union(ary_union, argv[i]);
return ary_union;
}
hash = ary_make_hash(ary);
for (i = 0; i < argc; i++) rb_ary_union_hash(hash, argv[i]);
return rb_hash_values(hash);
} Возвращает новый массив, содержащий объединение элементов self и всех заданных массивов other_arrays; элементы сравниваются с помощью eql?:
[0, 1, 2, 3].union([4, 5], [6, 7]) # => [0, 1, 2, 3, 4, 5, 6, 7]
Удаляет дубликаты (сохраняя первое найденное вхождение):
[0, 1, 1].union([2, 1], [3, 1]) # => [0, 1, 2, 3]
Сохраняет порядок (позицию первого найденного вхождения):
[3, 2, 1, 0].union([5, 3], [4, 2]) # => [3, 2, 1, 0, 5, 4]
Если аргументы не указаны, возвращает копию self.
Связанные методы: см. Методы объединения.
static VALUE
rb_ary_uniq(VALUE ary)
{
VALUE hash, uniq;
if (RARRAY_LEN(ary) <= 1) {
hash = 0;
uniq = rb_ary_dup(ary);
}
else if (rb_block_given_p()) {
hash = ary_make_hash_by(ary);
uniq = rb_hash_values(hash);
}
else {
hash = ary_make_hash(ary);
uniq = rb_hash_values(hash);
}
return uniq;
} Возвращает новый массив, содержащий элементы self без дубликатов; первое вхождение всегда сохраняется.
Если блок не указан, обнаруживает и исключает дублирующиеся элементы, сравнивая их с помощью метода eql?:
a = [0, 0, 1, 1, 2, 2] a.uniq # => [0, 1, 2]
Если блок указан, вызывает его для каждого элемента; обнаруживает и исключает «дублирующиеся» элементы, сравнивая возвращаемые блоком значения с помощью метода eql?; то есть элемент является дубликатом, если возвращаемое для него блоком значение совпадает со значением предыдущего элемента:
a = ['a', 'aa', 'aaa', 'b', 'bb', 'bbb']
a.uniq {|element| element.size } # => ["a", "aa", "aaa"]
Связанные методы: Методы извлечения.
static VALUE
rb_ary_uniq_bang(VALUE ary)
{
VALUE hash;
long hash_size;
rb_ary_modify_check(ary);
if (RARRAY_LEN(ary) <= 1)
return Qnil;
if (rb_block_given_p())
hash = ary_make_hash_by(ary);
else
hash = ary_make_hash(ary);
hash_size = RHASH_SIZE(hash);
if (RARRAY_LEN(ary) == hash_size) {
return Qnil;
}
rb_ary_modify_check(ary);
ARY_SET_LEN(ary, 0);
if (ARY_SHARED_P(ary)) {
rb_ary_unshare(ary);
FL_SET_EMBED(ary);
}
ary_resize_capa(ary, hash_size);
rb_hash_foreach(hash, push_value, ary);
return ary;
} Удаляет дублирующиеся элементы из self, всегда сохраняя первое вхождение; возвращает self, если были удалены какие-либо элементы, и nil в противном случае.
Если блок не указан, обнаруживает и удаляет элементы, сравнивая их с помощью метода eql?:
a = [0, 0, 1, 1, 2, 2] a.uniq! # => [0, 1, 2] a.uniq! # => nil
Если блок указан, вызывает его для каждого элемента; обнаруживает и исключает «дублирующиеся» элементы, сравнивая возвращаемые блоком значения с помощью метода eql?; то есть элемент является дубликатом, если возвращаемое для него блоком значение совпадает со значением предыдущего элемента:
a = ['a', 'aa', 'aaa', 'b', 'bb', 'bbb']
a.uniq! {|element| element.size } # => ["a", "aa", "aaa"]
a.uniq! {|element| element.size } # => nil
Связанные методы: см. Методы удаления.
VALUE
rb_ary_unshift_m(int argc, VALUE *argv, VALUE ary)
{
long len = RARRAY_LEN(ary);
VALUE target_ary;
if (argc == 0) {
rb_ary_modify_check(ary);
return ary;
}
target_ary = ary_ensure_room_for_unshift(ary, argc);
ary_memcpy0(ary, 0, argc, argv, target_ary);
ARY_SET_LEN(ary, len + argc);
return ary;
} Добавляет заданные objects в начало self:
a = [:foo, 'bar', 2] a.unshift(:bam, :bat) # => [:bam, :bat, :foo, "bar", 2]
Связанные методы: Array#shift; см. также Методы присваивания.
static VALUE
rb_ary_values_at(int argc, VALUE *argv, VALUE ary)
{
long i, olen = RARRAY_LEN(ary);
VALUE result = rb_ary_new_capa(argc);
for (i = 0; i < argc; ++i) {
append_values_at_single(result, ary, olen, argv[i]);
}
RB_GC_GUARD(ary);
return result;
} Возвращает элементы из self в новом массиве; self не изменяется.
Объекты в возвращаемом массиве — это элементы self, выбранные с помощью заданных specifiers, каждый из которых должен быть числовым индексом или Range.
Кратко:
a = ['a', 'b', 'c', 'd'] # Index specifiers. a.values_at(2, 0, 2, 0) # => ["c", "a", "c", "a"] # May repeat. a.values_at(-4, -3, -2, -1) # => ["a", "b", "c", "d"] # Counts backwards if negative. a.values_at(-50, 50) # => [nil, nil] # Outside of self. # Range specifiers. a.values_at(1..3) # => ["b", "c", "d"] # From range.begin to range.end. a.values_at(1...3) # => ["b", "c"] # End excluded. a.values_at(3..1) # => [] # No such elements. a.values_at(-3..3) # => ["b", "c", "d"] # Negative range.begin counts backwards. a.values_at(-50..3) # Raises RangeError. a.values_at(1..-2) # => ["b", "c"] # Negative range.end counts backwards. a.values_at(1..-50) # => [] # No such elements. # Mixture of specifiers. a.values_at(2..3, 3, 0..1, 0) # => ["c", "d", "d", "a", "b", "a"]
Если specifiers не указаны, возвращает новый пустой массив:
a = ['a', 'b', 'c', 'd'] a.values_at # => []
Для каждого числового спецификатора index включается элемент:
-
Для каждого неотрицательного числового спецификатора
index, находящегося в допустимом диапазоне (меньшеself.size), включается элемент со смещениемindex:a.values_at(0, 2) # => ["a", "c"] a.values_at(0.1, 2.9) # => ["a", "c"]
-
Для каждого отрицательного числового
index, находящегося в допустимом диапазоне (больше или равного- self.size), отсчёт ведётся с концаself:a.values_at(-1, -4) # => ["d", "a"]
Заданные индексы могут располагаться в любом порядке и повторяться:
a.values_at(2, 0, 1, 0, 2) # => ["c", "a", "b", "a", "c"]
Для каждого index, выходящего за допустимый диапазон, включается nil:
a.values_at(4, -5) # => [nil, nil]
Для каждого спецификатора Range range включаются элементы в соответствии с range.begin и range.end:
-
Если и
range.begin, иrange.endнеотрицательны и находятся в допустимом диапазоне (меньшеself.size), включаются элементы с индексаrange.beginпоrange.end - 1(еслиrange.exclude_end?) или поrange.end(в противном случае):a.values_at(1..2) # => ["b", "c"] a.values_at(1...2) # => ["b"]
-
Если
range.beginотрицателен и находится в допустимом диапазоне (больше или равен- self.size), отсчёт ведётся с концаself:a.values_at(-2..3) # => ["c", "d"]
-
Если
range.beginотрицателен и выходит за допустимый диапазон, возникает исключение:a.values_at(-5..3) # Raises RangeError.
-
Если
range.endположителен и выходит за допустимый диапазон, возвращаемый массив дополняется элементамиnil:a.values_at(1..5) # => ["b", "c", "d", nil, nil]
-
Если
range.endотрицателен и находится в допустимом диапазоне, отсчёт ведётся с концаself:a.values_at(1..-2) # => ["b", "c"]
-
Если
range.endотрицателен и выходит за допустимый диапазон, возвращается пустой массив:a.values_at(1..-5) # => []
Заданные диапазоны могут располагаться в любом порядке и повторяться:
a.values_at(2..3, 0..1, 2..3) # => ["c", "d", "a", "b", "c", "d"]
Заданные спецификаторы могут представлять собой любую комбинацию индексов и диапазонов:
a.values_at(3, 1..2, 0, 2..3) # => ["d", "b", "c", "a", "c", "d"]
Связанные методы: см. Методы извлечения.
static VALUE
rb_ary_zip(int argc, VALUE *argv, VALUE ary)
{
int i, j;
long len = RARRAY_LEN(ary);
VALUE result = Qnil;
for (i=0; i<argc; i++) {
argv[i] = take_items(argv[i], len);
}
if (rb_block_given_p()) {
int arity = rb_block_arity();
if (arity > 1) {
VALUE work, *tmp;
tmp = ALLOCV_N(VALUE, work, argc+1);
for (i=0; i<RARRAY_LEN(ary); i++) {
tmp[0] = RARRAY_AREF(ary, i);
for (j=0; j<argc; j++) {
tmp[j+1] = rb_ary_elt(argv[j], i);
}
rb_yield_values2(argc+1, tmp);
}
if (work) ALLOCV_END(work);
}
else {
for (i=0; i<RARRAY_LEN(ary); i++) {
VALUE tmp = rb_ary_new2(argc+1);
rb_ary_push(tmp, RARRAY_AREF(ary, i));
for (j=0; j<argc; j++) {
rb_ary_push(tmp, rb_ary_elt(argv[j], i));
}
rb_yield(tmp);
}
}
}
else {
result = rb_ary_new_capa(len);
for (i=0; i<len; i++) {
VALUE tmp = rb_ary_new_capa(argc+1);
rb_ary_push(tmp, RARRAY_AREF(ary, i));
for (j=0; j<argc; j++) {
rb_ary_push(tmp, rb_ary_elt(argv[j], i));
}
rb_ary_push(result, tmp);
}
}
return result;
} Если блок не указан, объединяет self с коллекцией other_arrays; возвращает новый массив подмассивов:
[0, 1].zip(['zero', 'one'], [:zero, :one]) # => [[0, "zero", :zero], [1, "one", :one]]
Возвращаемое значение:
-
Размер внешнего массива равен
self.size. -
Размер каждого подмассива равен
other_arrays.size + 1. -
n-й подмассив содержит (в указанном порядке):
-
n-й элемент
self. -
n-й элемент каждого из остальных массивов, если он существует.
-
Пример:
a = [0, 1] zipped = a.zip(['zero', 'one'], [:zero, :one]) # => [[0, "zero", :zero], [1, "one", :one]] zipped.size # => 2 # Same size as a. zipped.first.size # => 3 # Size of other arrays plus 1.
Если размеры всех остальных массивов совпадают с размером self, возвращаемые подмассивы представляют собой перестановку, содержащую в точности элементы всех массивов (включая self), без пропусков и добавлений:
a = [:a0, :a1, :a2, :a3] b = [:b0, :b1, :b2, :b3] c = [:c0, :c1, :c2, :c3] d = a.zip(b, c) pp d # => [[:a0, :b0, :c0], [:a1, :b1, :c1], [:a2, :b2, :c2], [:a3, :b3, :c3]]
Если один из остальных массивов меньше self, соответствующий подмассив дополняется элементами nil:
a = [:a0, :a1, :a2, :a3] b = [:b0, :b1, :b2] c = [:c0, :c1] d = a.zip(b, c) pp d # => [[:a0, :b0, :c0], [:a1, :b1, :c1], [:a2, :b2, nil], [:a3, nil, nil]]
Если один из остальных массивов больше self, его конечные элементы игнорируются:
a = [:a0, :a1, :a2, :a3] b = [:b0, :b1, :b2, :b3, :b4] c = [:c0, :c1, :c2, :c3, :c4, :c5] d = a.zip(b, c) pp d # => [[:a0, :b0, :c0], [:a1, :b1, :c1], [:a2, :b2, :c2], [:a3, :b3, :c3]]
Если блок указан, вызывает его с каждым из остальных массивов; возвращает nil:
d = []
a = [:a0, :a1, :a2, :a3]
b = [:b0, :b1, :b2, :b3]
c = [:c0, :c1, :c2, :c3]
a.zip(b, c) {|sub_array| d.push(sub_array.reverse) } # => nil
pp d
# =>
[[:c0, :b0, :a0],
[:c1, :b1, :a1],
[:c2, :b2, :a2],
[:c3, :b3, :a3]]
Для объекта в other_arrays, который на самом деле не является массивом, «остальной массив» формируется как object.to_ary, если он определён, или как object.each.to_a в противном случае.
Связанные методы: см. Методы преобразования.
Ruby Core © 1993–2025 Yukihiro Matsumoto
Licensed under the Ruby License.
Ruby Standard Library © contributors
Licensed under their own licenses.