класс Array
Массив — это упорядоченная коллекция объектов с целочисленными индексами, называемых элементами. Элементом массива может быть любой объект.
Индексы массива
Индексация массива начинается с 0, как в C или Java.
Положительный индекс — это смещение от первого элемента:
-
Индекс 0 обозначает первый элемент.
-
Индекс 1 обозначает второй элемент.
-
…
Отрицательный индекс — это смещение, назад, от конца массива:
-
Индекс -1 обозначает последний элемент.
-
Индекс -2 обозначает предпоследний элемент.
-
…
Неотрицательный индекс находится в пределах, если он меньше размера массива. Для массива из 3 элементов:
-
Индексы от 0 до 2 находятся в пределах.
-
Индекс 3 находится вне пределов.
Отрицательный индекс находится в пределах, если его абсолютное значение не больше размера массива. Для массива из 3 элементов:
-
Индексы от -1 до -3 находятся в пределах.
-
Индекс -4 находится вне пределов.
Создание массивов
Вы можете создать объект массива явно с помощью:
-
Литерала массива.
Вы можете преобразовать определённые объекты в массивы с помощью:
-
Метода Array.
Массив может содержать различные типы объектов. Например, массив ниже содержит Integer, String и число с плавающей точкой:
ary = [1, "two", 3.0] #=> [1, "two", 3.0]
Массив также можно создать, вызвав Array.new с нулём, одним (начальный размер Array) или двумя аргументами (начальный размер и значение по умолчанию).
ary = Array.new #=> [] Array.new(3) #=> [nil, nil, nil] Array.new(3, true) #=> [true, true, true]
Обратите внимание, что второй аргумент заполняет массив ссылками на один и тот же объект. Поэтому, это рекомендуется только в случаях, когда вам необходимо создать массивы с объектами, не изменяемыми по своей природе, такими как символы, числа, true или false.
Для создания массива с различными объектами можно передать блок вместо этого. Этот метод безопасен в использовании с изменяемыми объектами, такими как хэши, строки или другие массивы:
Array.new(4) {Hash.new} #=> [{}, {}, {}, {}]
Array.new(4) {|i| i.to_s } #=> ["0", "1", "2", "3"]
Это также быстрый способ построения многомерных массивов:
empty_table = Array.new(3) {Array.new(3)}
#=> [[nil, nil, nil], [nil, nil, nil], [nil, nil, nil]]
Массив также можно создать, используя метод Array(), предоставляемый Kernel, который пытается вызвать to_ary, а затем to_a на своём аргументе.
Array({:a => "a", :b => "b"}) #=> [[:a, "a"], [:b, "b"]]
Примеры использования
В дополнение к методам, включённым через модуль 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’s each все элементы экземпляра Array передаются в предоставленный блок последовательно.
Обратите внимание, что эта операция не изменяет массив.
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 -
Возвращает новый массив, созданный из данного объекта.
Методы запроса
-
length,size -
Возвращает количество элементов.
-
include? -
Возвращает значение, указывающее, содержит ли массив какой-либо элемент,
==заданный объект. -
empty? -
Возвращает значение, указывающее, пуст ли массив.
-
all? -
Возвращает значение, указывающее, удовлетворяют ли все элементы заданному критерию.
-
any? -
Возвращает значение, указывающее, удовлетворяет ли какой-либо элемент заданному критерию.
-
none? -
Возвращает значение, указывающее, не содержит ли массив ни одного элемента,
==заданный объект. -
one? -
Возвращает значение, указывающее, содержит ли массив ровно один элемент,
==заданный объект. -
count -
Возвращает количество элементов, удовлетворяющих заданному критерию.
-
find_index,index -
Возвращает индекс первого элемента, удовлетворяющего заданному критерию.
-
rindex -
Возвращает индекс последнего элемента, удовлетворяющего заданному критерию.
-
hash -
Возвращает целочисленный хэш-код.
Методы для сравнения
- #<=>
-
Возвращает -1, 0 или 1 в зависимости от того,
selfменьше, равно или больше заданного объекта. - #==
-
Возвращает значение, указывающее, совпадает ли каждый элемент в
selfс соответствующим элементом в заданном объекте. -
eql? -
Возвращает значение, указывающее, совпадает ли каждый элемент в
selfс соответствующим элементом в заданном объекте.
Методы для извлечения
Эти методы не изменяют self.
-
[] -
Возвращает один или несколько элементов.
-
fetch -
Возвращает элемент по заданному смещению.
-
first -
Возвращает один или несколько начальных элементов.
-
last -
Возвращает один или несколько конечных элементов.
-
max -
Возвращает один или несколько элементов с максимальным значением, определённым по
<=>или заданному блоку. -
max -
Возвращает один или несколько элементов с минимальным значением, определённым по
<=>или заданному блоку. -
minmax -
Возвращает элементы с минимальным и максимальным значением, определённым по
<=>или заданному блоку. -
assoc -
Возвращает первый элемент, который является массивом, первый элемент которого
==заданный объект. -
rassoc -
Возвращает первый элемент, который является массивом, второй элемент которого
==заданный объект. -
at -
Возвращает элемент по заданному смещению.
-
values_at -
Возвращает элементы по заданным смещениям.
-
dig -
Возвращает объект во вложенных объектах, указанный заданным индексом и дополнительными аргументами.
-
drop -
Возвращает конечные элементы, определённые заданным индексом.
-
take -
Возвращает начальные элементы, определённые заданным индексом.
-
drop_while -
Возвращает конечные элементы, определённые заданным блоком.
-
take_while -
Возвращает начальные элементы, определённые заданным блоком.
-
slice -
Возвращает последовательные элементы, определённые заданным аргументом.
-
sort -
Возвращает все элементы в порядке, определённом по
<=>или заданному блоку. -
reverse -
Возвращает все элементы в обратном порядке.
-
compact -
Возвращает массив, содержащий все не-
nilэлементы. -
select,filter -
Возвращает массив, содержащий выбранные элементы заданным блоком.
-
uniq -
Возвращает массив, содержащий уникальные элементы.
-
rotate -
Возвращает все элементы с некоторыми, сдвинутыми с одного конца на другой.
-
bsearch -
Возвращает элемент, выбранный с помощью бинарного поиска, определённого заданным блоком.
-
bsearch_index -
Возвращает индекс элемента, выбранного с помощью бинарного поиска, определённого заданным блоком.
-
sample -
Возвращает один или несколько случайных элементов.
-
shuffle -
Возвращает элементы в случайном порядке.
Методы для присвоения
Эти методы добавляют, заменяют или переупорядочивают элементы в self.
-
[]= -
Присваивает указанные элементы заданному объекту.
-
push,append,<< -
Добавляет конечные элементы.
-
unshift,prepend -
Добавляет начальные элементы.
-
insert -
Вставляет заданные объекты по заданному смещению; не заменяет элементы.
-
concat -
Добавляет все элементы из заданных массивов.
-
fill -
Заменяет указанные элементы заданными объектами.
-
replace -
Заменяет содержимое
selfсодержимым заданного массива. -
reverse! -
Заменяет
selfсвоими элементами в обратном порядке. -
rotate! -
Заменяет
selfсвоими элементами, сдвинутыми. -
shuffle! -
Заменяет
selfсвоими элементами в случайном порядке. -
sort! -
Заменяет
selfсвоими отсортированными элементами, определёнными по<=>или заданному блоку. -
sort_by! -
Заменяет
selfсвоими элементами, отсортированными по заданному блоку.
Методы для удаления
Каждый из этих методов удаляет элементы из self:
-
pop -
Удаляет и возвращает последний элемент.
-
shift -
Удаляет и возвращает первый элемент.
-
compact! -
Удаляет все не-
nilэлементы. -
delete -
Удаляет элементы, равные заданному объекту.
-
delete_at -
Удаляет элемент по заданному смещению.
-
delete_if -
Удаляет элементы, указанные заданным блоком.
-
keep_if -
Удаляет элементы, не указанные заданным блоком.
-
reject! -
Удаляет элементы, указанные заданным блоком.
-
select!,filter! -
Удаляет элементы, не указанные заданным блоком.
-
slice! -
Удаляет и возвращает последовательность элементов.
-
uniq! -
Удаляет дубликаты.
Методы для объединения
- #&
-
Возвращает массив, содержащий элементы, присутствующие как в
self, так и в заданном массиве. -
intersection -
Возвращает массив, содержащий элементы, присутствующие как в
self, так и в каждом из переданных массивов. -
+ -
Возвращает массив, содержащий все элементы
self, за которыми следуют все элементы переданного массива. -
- -
Возвращает массив, содержащий все элементы
self, которые не присутствуют в заданном массиве. - #|
-
Возвращает массив, содержащий все элементы
selfи все элементы заданного массива, с удалением дубликатов. -
union -
Возвращает массив, содержащий все элементы
selfи все элементы переданных массивов, с удалением дубликатов. -
difference -
Возвращает массив, содержащий все элементы
self, которые не присутствуют ни в одном из переданных массивов. -
product -
Возвращает или выводит все комбинации элементов из
selfи переданных массивов.
Методы для итерации
-
each -
Передает каждый элемент в заданный блок.
-
reverse_each -
Передает каждый элемент в обратном порядке в заданный блок.
-
each_index -
Передает индекс каждого элемента в заданный блок.
-
cycle -
Вызывает заданный блок с каждым элементом, затем снова и снова, для указанного количества раз или бесконечно.
-
combination -
Вызывает заданный блок с комбинациями элементов
self; комбинация не использует один и тот же элемент более одного раза. -
permutation -
Вызывает заданный блок с перестановками элементов
self; перестановка не использует один и тот же элемент более одного раза. -
repeated_combination -
Вызывает заданный блок с комбинациями элементов
self; комбинация может использовать один и тот же элемент более одного раза. -
repeated_permutation -
Вызывает заданный блок с перестановками элементов
self; перестановка может использовать один и тот же элемент более одного раза.
Методы для преобразования
-
map,collect -
Возвращает массив, содержащий значение, возвращаемое блоком для каждого элемента.
-
map!,collect! -
Заменяет каждый элемент значением, возвращаемым блоком.
-
flatten -
Возвращает массив, представляющий рекурсивное развёртывание
self. -
flatten! -
Заменяет каждый вложенный массив в
selfэлементами из этого массива. -
inspect,to_s -
Возвращает новый
String, содержащий элементы. -
join -
Возвращает новую строку, содержащую элементы, соединённые с помощью разделителя.
-
to_a -
Возвращает
selfили новый массив, содержащий все элементы. -
to_ary -
Возвращает
self. -
to_h -
Возвращает новый хэш, сформированный из элементов.
-
transpose -
Транспонирует
self, который должен быть массивом массивов. -
zip -
Возвращает новый массив массивов, содержащий
selfи заданные массивы; подробности см. по ссылке.
Другие методы
-
* -
Возвращает одно из следующих:
-
С целочисленным аргументом
n, новый массив, являющийся конкатенациейnкопийself. -
Со строковым аргументом
field_separator, новую строку, эквивалентнуюjoin(field_separator).
-
-
abbrev -
Возвращает хэш недвусмысленных сокращений для элементов.
-
pack -
Упаковывает элементы в двоичную последовательность.
-
sum -
Возвращает сумму элементов, согласно
+или заданному блоку.
for pack.c
Методы публичного класса
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[ 1, 'a', /^A/ ] # => [1, "a", /^A/] [ 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) {
if (ARY_OWNS_HEAP_P(ary) && ARY_HEAP_PTR(ary) != NULL) {
ary_heap_free(ary);
}
rb_ary_unshare_safe(ary);
FL_SET_EMBED(ary);
ARY_SET_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, возвращает новый массив, сформированный из array:
a = Array.new([:foo, 'bar', 2]) a.class # => Array a # => [:foo, "bar", 2]
Без блока и с единственным целым числом-аргументом size, возвращает новый массив заданного размера, каждый элемент которого равен nil:
a = Array.new(3) a # => [nil, nil, nil]
Без блока и с аргументами size и default_value, возвращает массив заданного размера; каждый элемент равен тому же default_value:
a = Array.new(3, 'x') a # => ['x', 'x', 'x']
С блоком и аргументом size, возвращает массив заданного размера; блок вызывается с каждым последующим целым числом index; элемент для этого index — значение, возвращаемое блоком:
a = Array.new(3) {|index| "Element #{index}" }
a # => ["Element 0", "Element 1", "Element 2"]
Вызывает ArgumentError, если size отрицательно.
С блоком и без аргумента или с одним аргументом 0, игнорирует блок и возвращает новый пустой массив.
static VALUE
rb_ary_s_try_convert(VALUE dummy, VALUE ary)
{
return rb_check_array_type(ary);
} Если object является объектом массива, возвращает object.
В противном случае, если object отвечает на :to_ary, вызывает object.to_ary и возвращает результат.
Возвращает nil если object не отвечает на :to_ary
Вызывает исключение, если object.to_ary не возвращает объект массива.
Методы открытого экземпляра
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);
}
}
ary_recycle_hash(hash);
return ary3;
} Возвращает новый массив, содержащий каждый элемент, найденный как в array, так и в массиве other_array; дубликаты опускаются; элементы сравниваются с использованием eql?;
[0, 1, 2, 3] & [1, 2] # => [1, 2] [0, 1, 0, 1] & [0, 1] # => [0, 1]
Порядок из array сохраняется:
[0, 1, 2] & [3, 2, 1, 0] # => [0, 1, 2]
Связанно с: Array#intersection.
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_TRANSIENT(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_TRANSIENT(ary2));
t *= 2;
}
if (t < len) {
ary_memcpy(ary2, t, len-t, RARRAY_CONST_PTR_TRANSIENT(ary2));
}
}
out:
return ary2;
} При задании целочисленного аргумента n неотрицательной величины, возвращает новый массив, созданный путем конкатенации n копий self:
a = ['x', 'y'] a * 3 # => ["x", "y", "x", "y", "x", "y"]
При задании строкового аргумента string_separator эквивалентно array.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_TRANSIENT(x));
ary_memcpy(z, xlen, ylen, RARRAY_CONST_PTR_TRANSIENT(y));
ARY_SET_LEN(z, len);
return z;
} Возвращает новый массив, содержащий все элементы array вслед за всеми элементами other_array:
a = [0, 1] + [2, 3] a # => [0, 1, 2, 3]
Связанно с: concat.
static 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));
}
ary_recycle_hash(hash);
return ary3;
} Возвращает новый массив, содержащий только те элементы из array, которые не найдены в массиве other_array; элементы сравниваются с использованием eql?; порядок из array сохраняется:
[0, 1, 1, 2, 1, 1, 3, 1, 1] - [1] # => [0, 2, 3] [0, 1, 2, 3] - [3, 0] # => [1, 2] [0, 1, 2] - [4] # => [0, 1, 2]
Связанно с: Array#difference.
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_TRANSIENT(ary, ptr, {
RB_OBJ_WRITE(target_ary, &ptr[idx], item);
});
ARY_SET_LEN(ary, idx + 1);
ary_verify(ary);
return ary;
} Добавляет object в self; возвращает self:
a = [:foo, 'bar', 2] a << :baz # => [:foo, "bar", 2, :baz]
Добавляет object как один элемент, даже если это другой массив:
a = [:foo, 'bar', 2] a1 = a << [3, 4] a1 # => [: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 (v != Qundef) 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 в self, вычисляет result = self[i] <=> other_array[i].
Возвращает -1, если любой результат -1:
[0, 1, 2] <=> [0, 1, 3] # => -1
Возвращает 1, если любой результат 1:
[0, 1, 2] <=> [0, 1, 1] # => 1
Когда все результаты равны нулю:
-
Возвращает -1, если
arrayменьше, чемother_array:[0, 1, 2] <=> [0, 1, 2, 3] # => -1
-
Возвращает 1, если
arrayбольше, чемother_array:[0, 1, 2] <=> [0, 1] # => 1
-
Возвращает 0, если
arrayиother_arrayимеют одинаковый размер:[0, 1, 2] <=> [0, 1, 2] # => 0
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_TRANSIENT(ary1) == RARRAY_CONST_PTR_TRANSIENT(ary2)) return Qtrue;
return rb_exec_recursive_paired(recursive_equal, ary1, ary2, ary2);
} Возвращает true если оба array.size == other_array.size и для каждого индекса i в array, array[i] == other_array[i]:
a0 = [:foo, 'bar', 2] a1 = [:foo, 'bar', 2.0] a1 == a0 # => true [] == [] # => true
В противном случае, возвращает false.
Этот метод отличается от метода 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.
При задании одного целочисленного аргумента 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.
При задании двух целочисленных аргументов 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 + length и length >= 0, возвращает новый пустой массив.
Если length отрицательное, возвращает nil.
При задании одного аргумента типа диапазон 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, возвращает массив Array элементов, соответствующих индексам, сгенерированным последовательностью.
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]
Array#slice является псевдонимом для Array#[].
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.
Когда передан целочисленный аргумент 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"]
Когда переданы целочисленные аргументы 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, присваивает 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"]
# File lib/abbrev.rb, line 129 def abbrev(pattern = nil) Abbrev::abbrev(self, pattern) end
Вычисляет набор недвусмысленных сокращений для строк в self.
require 'abbrev'
%w{ car cone }.abbrev
#=> {"car"=>"car", "ca"=>"car", "cone"=>"cone", "con"=>"cone", "co"=>"cone"}
Необязательный параметр pattern — это шаблон или строка. Только входные строки, которые соответствуют шаблону или начинаются с этой строки, включаются в выходной хеш.
%w{ fast boat day }.abbrev(/^.a/)
#=> {"fast"=>"fast", "fas"=>"fast", "fa"=>"fast", "day"=>"day", "da"=>"day"}
Abbrev.abbrev(%w{car box cone}, "ca")
#=> {"car"=>"car", "ca"=>"car"}
См. также Abbrev.abbrev
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;
} Возвращает true если все элементы self удовлетворяют заданному критерию.
Без блока и без аргумента, возвращает true если self содержит только истинные значения, false в противном случае:
[0, 1, :foo].all? # => true [0, nil, 2].all? # => false [].all? # => true
С блоком и без аргумента, вызывает блок с каждым элементом в self; возвращает true если блок возвращает только истинные значения, false в противном случае:
[0, 1, 2].all? { |element| element < 3 } # => true
[0, 1, 2].all? { |element| element < 2 } # => false
Если передан аргумент obj , возвращает true если obj.=== каждый элемент, false в противном случае:
['food', 'fool', 'foot'].all?(/foo/) # => true ['food', 'drink'].all?(/bar/) # => false [].all?(/foo/) # => true [0, 0, 0].all?(0) # => true [0, 1, 2].all?(1) # => false
Связанно с: Enumerable#all?
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;
} Возвращает true если любой элемент self удовлетворяет заданному критерию.
Без блока и без аргумента, возвращает true если self содержит хотя бы один истинный элемент, false в противном случае:
[nil, 0, false].any? # => true [nil, false].any? # => false [].any? # => false
С блоком и без аргумента, вызывает блок с каждым элементом в self; возвращает true если блок возвращает какое-либо истинное значение, false в противном случае:
[0, 1, 2].any? {|element| element > 1 } # => true
[0, 1, 2].any? {|element| element > 2 } # => false
Если передан аргумент obj , возвращает true если obj.=== любой элемент, false в противном случае:
['food', 'drink'].any?(/foo/) # => true ['food', 'drink'].any?(/bar/) # => false [].any?(/foo/) # => false [0, 1, 2].any?(1) # => true [0, 1, 2].any?(3) # => false
Связанно с: Enumerable#any?
Добавляет конечные элементы.
Добавляет каждый аргумент в objects к self; возвращает self:
a = [:foo, 'bar', 2] a.push(:baz, :bat) # => [:foo, "bar", 2, :baz, :bat]
Добавляет каждый аргумент как один элемент, даже если это другой массив:
a = [:foo, 'bar', 2] a1 = a.push([:baz, :bat], [:bam, :bad]) a1 # => [:foo, "bar", 2, [:baz, :bat], [:bam, :bad]]
Array#append — псевдоним для Array#push.
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;
} Возвращает первый элемент в self, который является массивом, чьё первое значение == obj:
a = [{foo: 0}, [2, 4], [4, 5, 6], [4, 5]]
a.assoc(4) # => [4, 5, 6]
Возвращает nil если такой элемент не найден.
Связанно с: rassoc.
VALUE
rb_ary_at(VALUE ary, VALUE pos)
{
return rb_ary_entry(ary, NUM2LONG(pos));
} Возвращает элемент по целочисленному смещению index; не изменяет self.
a = [:foo, 'bar', 2] a.at(0) # => :foo a.at(2) # => 2
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, выбранный с помощью двоичного поиска.
См. Двоичный поиск.
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 = 1; break;
case -1: smaller = 0;
}
}
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 как описано в методе bsearch, но возвращает индекс найденного элемента вместо самого элемента.
VALUE
rb_ary_clear(VALUE ary)
{
rb_ary_modify_check(ary);
if (ARY_SHARED_P(ary)) {
if (!ARY_EMBED_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:
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]
Возвращает новый перечислитель, если блок не задан:
a = [:foo, 'bar', 2] a1 = a.map a1 # => #<Enumerator: [:foo, "bar", 2]:map>
Array#collect — псевдоним для Array#map.
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;
} Вызывает блок для каждого элемента; заменяет элемент значением, возвращаемым блоком:
a = [:foo, 'bar', 2]
a.map! { |element| element.class } # => [Symbol, String, Integer]
Возвращает новый перечислитель, если блок не указан:
a = [:foo, 'bar', 2] a1 = a.map! a1 # => #<Enumerator: [:foo, "bar", 2]:map!>
Array#collect! — псевдоним для Array#map!.
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;
} Вызывает блок, если он задан, с комбинациями элементов массива; возвращает само значение. Порядок комбинаций неопределён.
Если задан блок и целочисленный аргумент n (0 < n <= self.size) больше нуля, вызывает блок со всеми комбинациями элементов по n элементов массива self.
Пример:
a = [0, 1, 2]
a.combination(2) {|combination| p combination }
Вывод:
[0, 1] [0, 2] [1, 2]
Другой пример:
a = [0, 1, 2]
a.combination(3) {|combination| p combination }
Вывод:
[0, 1, 2]
Если n равно нулю, вызывает блок один раз с пустым массивом:
a = [0, 1, 2]
a1 = a.combination(0) {|combination| p combination }
Вывод:
[]
Если n находится вне диапазона (отрицательное или больше, чем self.size), не вызывает блок:
a = [0, 1, 2]
a.combination(-1) {|combination| fail 'Cannot happen' }
a.combination(4) {|combination| fail 'Cannot happen' }
Возвращает новый перечислитель, если блок не задан:
a = [0, 1, 2] a.combination(2) # => #<Enumerator: [0, 1, 2]:combination(2)>
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, 1, nil, 2, nil] a.compact # => [0, 1, 2]
static VALUE
rb_ary_compact_bang(VALUE ary)
{
VALUE *p, *t, *end;
long n;
rb_ary_modify(ary);
p = t = (VALUE *)RARRAY_CONST_PTR_TRANSIENT(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_TRANSIENT(ary);
if (RARRAY_LEN(ary) == n) {
return Qnil;
}
ary_resize_smaller(ary, n);
return ary;
} Удаляет все nil элементы из массива self.
Возвращает self если какие-либо элементы были удалены, иначе nil.
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_tmp_new(argc);
for (i = 0; i < argc; i++) {
rb_ary_concat(args, argv[i]);
}
ary_append(ary, args);
}
ary_verify(ary);
return ary;
} Добавляет к массиву все элементы из каждого массива в списке other_arrays; возвращает исходный массив self:
a = [0, 1] a.concat([2, 3], [4, 5]) # => [0, 1, 2, 3, 4, 5]
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, 1, 2].count # => 3 [].count # => 0
С аргументом obj, возвращает количество элементов от == до obj:
[0, 1, 2, 0.0].count(0) # => 2 [0, 1, 2].count(3) # => 0
Без аргумента и с заданным блоком, вызывает блок для каждого элемента; возвращает количество элементов, для которых блок возвращает истинное значение:
[0, 1, 2, 3].count {|element| element > 1} # => 2
С аргументом obj и заданным блоком, выводит предупреждение, игнорирует блок и возвращает количество элементов от == до obj:
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:
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
Если задан блок, а аргумент опущен или nil, цикл повторяется бесконечно:
# Prints 0 and 1 forever.
[0, 1].cycle {|element| puts element }
[0, 1].cycle(nil) {|element| puts element }
Если блок не задан, возвращает новый перечислитель:
[0, 1].cycle(2) # => #<Enumerator: [0, 1]:cycle(2)> [0, 1].cycle # => # => #<Enumerator: [0, 1]:cycle> [0, 1].cycle.first(5) # => [0, 1, 0, 1, 0]
static VALUE
rb_ary_deconstruct(VALUE ary)
{
return ary;
} 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.
Если блок не задан, удаляет из массива self каждый элемент ele такой, что ele == obj; возвращает последний удалённый элемент:
s1 = 'bar'; s2 = 'bar'
a = [:foo, s1, 2, s2]
a.delete('bar') # => "bar"
a # => [:foo, 2]
Возвращает nil если не удалено ни одного элемента.
Если задан блок, удаляет из массива self каждый элемент ele такой, что ele == obj.
Если такие элементы найдены, игнорирует блок и возвращает последний удалённый элемент:
s1 = 'bar'; s2 = 'bar'
a = [:foo, s1, 2, s2]
deleted_obj = a.delete('bar') {|obj| fail 'Cannot happen' }
a # => [:foo, 2]
Если такие элементы не найдены, возвращает значение, возвращённое блоком:
a = [:foo, 'bar', 2]
a.delete(:nosuch) {|obj| "#{obj} not found" } # => "nosuch 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]
Если индекс слишком большой, возвращает nil.
Если index отрицательный, счёт ведётся от конца массива:
a = [:foo, 'bar', 2] a.delete_at(-2) # => "bar" a # => [:foo, 2]
Если index слишком малый (далеко от нуля), возвращает 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]
Возвращает новый перечислитель, если блок не задан:
a = [:foo, 'bar', 2] a.delete_if # => #<Enumerator: [:foo, "bar", 2]:delete_if>
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], RARRAY_AREF(ary, i), 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]
Возвращает копию массива 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 за исключением первых n элементов, где n - неотрицательное целое число; не изменяет исходный массив 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]
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; не изменяет self.
Если указан блок, вызывает блок с каждым последующим элементом self; останавливается, если блок возвращает false или nil; возвращает новый Array без тех элементов, для которых блок вернул истинное значение:
a = [0, 1, 2, 3, 4, 5]
a.drop_while {|element| element < 3 } # => [3, 4, 5]
Без блока возвращает новый перечислитель:
[0, 1].drop_while # => # => #<Enumerator: [0, 1]:drop_while>
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:
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
Если блок не указан, возвращает новый перечислитель:
a = [:foo, 'bar', 2]
e = a.each
e # => #<Enumerator: [:foo, "bar", 2]:each>
a1 = e.each {|element| puts "#{element.class} #{element}" }
Вывод:
Symbol foo String bar Integer 2
Связанные: each_index, reverse_each.
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:
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 }
Вывод:
0 1
Если блок не указан, возвращает новый перечислитель:
a = [:foo, 'bar', 2]
e = a.each_index
e # => #<Enumerator: [:foo, "bar", 2]:each_index>
a1 = e.each {|index| puts "#{index} #{a[index]}"}
Вывод:
0 foo 1 bar 2 2
Связанные: each, reverse_each.
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_TRANSIENT(ary1) == RARRAY_CONST_PTR_TRANSIENT(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);
} Возвращает элемент по смещению index.
С единственным аргументом Integer index, возвращает элемент по смещению index:
a = [:foo, 'bar', 2] a.fetch(1) # => "bar"
Если index отрицателен, отсчитывается от конца массива:
a = [:foo, 'bar', 2] a.fetch(-1) # => 2 a.fetch(-2) # => "bar"
С аргументами index и default_value, возвращает элемент по смещению index, если индекс находится в диапазоне, в противном случае возвращает default_value:
a = [:foo, 'bar', 2] a.fetch(1, nil) # => "bar"
С аргументом index и блоком возвращает элемент по смещению index, если индекс находится в диапазоне (и блок не вызывается); в противном случае вызывает блок с индексом и возвращает его возвращаемое значение:
a = [:foo, 'bar', 2]
a.fetch(1) {|index| raise 'Cannot happen' } # => "bar"
a.fetch(50) {|index| "Value for #{index}" } # => "Value for 50"
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 (item == Qundef) {
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.
С аргументом obj и без блока заменяет все элементы на этот один объект:
a = ['a', 'b', 'c', 'd'] a # => ["a", "b", "c", "d"] a.fill(:X) # => [:X, :X, :X, :X]
С аргументами obj и Integer start, и без блока, заменяет элементы на основе заданного начала.
Если start находится в диапазоне (0 <= start < array.size), заменяет все элементы со смещения start до конца:
a = ['a', 'b', 'c', 'd'] a.fill(:X, 2) # => ["a", "b", :X, :X]
Если start слишком велико (start >= array.size), ничего не делает:
a = ['a', 'b', 'c', 'd'] a.fill(:X, 4) # => ["a", "b", "c", "d"] a = ['a', 'b', 'c', 'd'] a.fill(:X, 5) # => ["a", "b", "c", "d"]
Если start отрицательно, отсчитывается от конца (начальный индекс равен start + array.size):
a = ['a', 'b', 'c', 'd'] a.fill(:X, -2) # => ["a", "b", :X, :X]
Если start слишком мало (меньше и далеко от нуля), заменяет все элементы:
a = ['a', 'b', 'c', 'd'] a.fill(:X, -6) # => [:X, :X, :X, :X] a = ['a', 'b', 'c', 'd'] a.fill(:X, -50) # => [:X, :X, :X, :X]
С аргументами obj, Integer start, и Integer length, и без блока, заменяет элементы на основе заданных start и length.
Если start находится в диапазоне, заменяет length элементов, начиная со смещения start:
a = ['a', 'b', 'c', 'd'] a.fill(:X, 1, 1) # => ["a", :X, "c", "d"]
Если start отрицательно, отсчитывается от конца:
a = ['a', 'b', 'c', 'd'] a.fill(:X, -2, 1) # => ["a", "b", :X, "d"]
Если start велико (start >= array.size), расширяет self с nil:
a = ['a', 'b', 'c', 'd'] a.fill(:X, 5, 0) # => ["a", "b", "c", "d", nil] a = ['a', 'b', 'c', 'd'] a.fill(:X, 5, 2) # => ["a", "b", "c", "d", nil, :X, :X]
Если length равно нулю или меньше, не заменяет элементы:
a = ['a', 'b', 'c', 'd'] a.fill(:X, 1, 0) # => ["a", "b", "c", "d"] a.fill(:X, 1, -1) # => ["a", "b", "c", "d"]
С аргументами obj и Range range, и без блока, заменяет элементы на основе заданного диапазона.
Если диапазон положителен и возрастающий (0 < range.begin <= range.end), заменяет элементы от range.begin до range.end:
a = ['a', 'b', 'c', 'd'] a.fill(:X, (1..1)) # => ["a", :X, "c", "d"]
Если range.first отрицательно, не заменяет элементы:
a = ['a', 'b', 'c', 'd'] a.fill(:X, (-1..1)) # => ["a", "b", "c", "d"]
Если range.last отрицательно, отсчитывается от конца:
a = ['a', 'b', 'c', 'd'] a.fill(:X, (0..-2)) # => [:X, :X, :X, "d"] a = ['a', 'b', 'c', 'd'] a.fill(:X, (1..-2)) # => ["a", :X, :X, "d"]
Если range.last и range.last оба отрицательны, оба отсчитываются от конца массива:
a = ['a', 'b', 'c', 'd'] a.fill(:X, (-1..-1)) # => ["a", "b", "c", :X] a = ['a', 'b', 'c', 'd'] a.fill(:X, (-2..-2)) # => ["a", "b", :X, "d"]
Без аргументов и с блоком вызывает блок с каждым индексом; заменяет соответствующий элемент возвращаемым значением блока:
a = ['a', 'b', 'c', 'd']
a.fill { |index| "new_#{index}" } # => ["new_0", "new_1", "new_2", "new_3"]
С аргументом start и блоком вызывает блок с каждым индексом от смещения start до конца; заменяет соответствующий элемент возвращаемым значением блока:
Если начало находится в диапазоне (0 <= start < array.size), заменяет со смещения start до конца:
a = ['a', 'b', 'c', 'd']
a.fill(1) { |index| "new_#{index}" } # => ["a", "new_1", "new_2", "new_3"]
Если start слишком велико (start >= array.size), ничего не делает:
a = ['a', 'b', 'c', 'd']
a.fill(4) { |index| fail 'Cannot happen' } # => ["a", "b", "c", "d"]
a = ['a', 'b', 'c', 'd']
a.fill(4) { |index| fail 'Cannot happen' } # => ["a", "b", "c", "d"]
Если start отрицательно, отсчитывается от конца:
a = ['a', 'b', 'c', 'd']
a.fill(-2) { |index| "new_#{index}" } # => ["a", "b", "new_2", "new_3"]
Если начало слишком мало (start <= -array.size, заменяет все элементы:
a = ['a', 'b', 'c', 'd']
a.fill(-6) { |index| "new_#{index}" } # => ["new_0", "new_1", "new_2", "new_3"]
a = ['a', 'b', 'c', 'd']
a.fill(-50) { |index| "new_#{index}" } # => ["new_0", "new_1", "new_2", "new_3"]
С аргументами start и length, и блоком вызывает блок для каждого индекса, указанного началом длины; заменяет соответствующий элемент возвращаемым значением блока.
Если start находится в диапазоне, заменяет length элементов, начиная со смещения start:
a = ['a', 'b', 'c', 'd']
a.fill(1, 1) { |index| "new_#{index}" } # => ["a", "new_1", "c", "d"]
Если начало отрицательно, отсчитывается от конца:
a = ['a', 'b', 'c', 'd']
a.fill(-2, 1) { |index| "new_#{index}" } # => ["a", "b", "new_2", "d"]
Если start велико (start >= array.size), расширяет self с nil:
a = ['a', 'b', 'c', 'd']
a.fill(5, 0) { |index| "new_#{index}" } # => ["a", "b", "c", "d", nil]
a = ['a', 'b', 'c', 'd']
a.fill(5, 2) { |index| "new_#{index}" } # => ["a", "b", "c", "d", nil, "new_5", "new_6"]
Если length равно нулю или меньше, не заменяет элементы:
a = ['a', 'b', 'c', 'd']
a.fill(1, 0) { |index| "new_#{index}" } # => ["a", "b", "c", "d"]
a.fill(1, -1) { |index| "new_#{index}" } # => ["a", "b", "c", "d"]
С аргументами obj и range, и блоком вызывает блок с каждым индексом в заданном диапазоне; заменяет соответствующий элемент возвращаемым значением блока.
Если диапазон положителен и возрастающий (range 0 < range.begin <= range.end, заменяет элементы от range.begin до range.end:
a = ['a', 'b', 'c', 'd']
a.fill(1..1) { |index| "new_#{index}" } # => ["a", "new_1", "c", "d"]
Если range.first отрицательно, ничего не делает:
a = ['a', 'b', 'c', 'd']
a.fill(-1..1) { |index| fail 'Cannot happen' } # => ["a", "b", "c", "d"]
Если range.last отрицательно, отсчитывается от конца:
a = ['a', 'b', 'c', 'd']
a.fill(0..-2) { |index| "new_#{index}" } # => ["new_0", "new_1", "new_2", "d"]
a = ['a', 'b', 'c', 'd']
a.fill(1..-2) { |index| "new_#{index}" } # => ["a", "new_1", "new_2", "d"]
Если range.first и range.last оба отрицательны, оба отсчитываются от конца:
a = ['a', 'b', 'c', 'd']
a.fill(-1..-1) { |index| "new_#{index}" } # => ["a", "b", "c", "new_3"]
a = ['a', 'b', 'c', 'd']
a.fill(-2..-2) { |index| "new_#{index}" } # => ["a", "b", "new_2", "d"]
Вызывает блок, если он задан, с каждым элементом self; возвращает новый массив, содержащий те элементы self, для которых блок возвращает истинное значение:
a = [:foo, 'bar', 2, :bam]
a1 = a.select {|element| element.to_s.start_with?('b') }
a1 # => ["bar", :bam]
Возвращает новый перечислитель, если блок не задан:
a = [:foo, 'bar', 2, :bam] a.select # => #<Enumerator: [:foo, "bar", 2, :bam]:select>
Array#filter является псевдонимом для Array#select.
Вызывает блок, если он задан, с каждым элементом self; удаляет из self те элементы, для которых блок возвращает false или nil.
Возвращает self , если какие-либо элементы были удалены:
a = [:foo, 'bar', 2, :bam]
a.select! {|element| element.to_s.start_with?('b') } # => ["bar", :bam]
Возвращает nil , если элементы не были удалены.
Возвращает новый перечислитель, если блок не задан:
a = [:foo, 'bar', 2, :bam] a.select! # => #<Enumerator: [:foo, "bar", 2, :bam]:select!>
Array#filter! является псевдонимом для Array#select!.
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;
} Возвращает индекс указанного элемента.
Если аргумент object задан, но блок нет, возвращает индекс первого элемента element, для которого object == element:
a = [:foo, 'bar', 2, 'bar']
a.index('bar') # => 1
Возвращает nil , если такой элемент не найден.
Если и аргумент object и блок заданы, вызывает блок с каждым последующим элементом; возвращает индекс первого элемента, для которого блок возвращает истинное значение:
a = [:foo, 'bar', 2, 'bar']
a.index {|element| element == 'bar' } # => 1
Возвращает nil , если блок никогда не возвращает истинное значение.
Если ни аргумент, ни блок не заданы, возвращает новый перечислитель:
a = [:foo, 'bar', 2]
e = a.index
e # => #<Enumerator: [:foo, "bar", 2]:index>
e.each {|element| element == 'bar' } # => 1
Array#find_index является псевдонимом для Array#index.
Связанные: rindex.
static VALUE
rb_ary_first(int argc, VALUE *argv, VALUE ary)
{
if (argc == 0) {
if (RARRAY_LEN(ary) == 0) return Qnil;
return RARRAY_AREF(ary, 0);
}
else {
return ary_take_first_or_last(argc, argv, ary, ARY_TAKE_FIRST);
}
} Возвращает элементы из self; не изменяет self.
Если аргумент не задан, возвращает первый элемент:
a = [:foo, 'bar', 2] a.first # => :foo a # => [:foo, "bar", 2]
Если self пуст, возвращает nil.
Если аргумент n - положительное целое число, возвращает первые n элементов в новом массиве:
a = [:foo, 'bar', 2] a.first(2) # => [:foo, "bar"]
Если n >= array.size, возвращает все элементы:
a = [:foo, 'bar', 2] a.first(50) # => [:foo, "bar", 2]
Если n == 0 возвращает новый пустой массив:
a = [:foo, 'bar', 2] a.first(0) # []
Связанные: last.
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:
-
Каждый элемент, не являющийся массивом, остается без изменений.
-
Каждый массив заменяется своими отдельными элементами.
С аргументом level - положительным целым числом, рекурсивно разлагает по level уровням:
a = [ 0, [ 1, [2, 3], 4 ], 5 ] a.flatten(0) # => [0, [1, [2, 3], 4], 5] a = [ 0, [ 1, [2, 3], 4 ], 5 ] a.flatten(1) # => [0, 1, [2, 3], 4, 5] a = [ 0, [ 1, [2, 3], 4 ], 5 ] a.flatten(2) # => [0, 1, 2, 3, 4, 5] a = [ 0, [ 1, [2, 3], 4 ], 5 ] a.flatten(3) # => [0, 1, 2, 3, 4, 5]
Без аргумента, с аргументом nil или с отрицательным аргументом level, разлагает все уровни:
a = [ 0, [ 1, [2, 3], 4 ], 5 ] a.flatten # => [0, 1, 2, 3, 4, 5] [0, 1, 2].flatten # => [0, 1, 2] a = [ 0, [ 1, [2, 3], 4 ], 5 ] a.flatten(-1) # => [0, 1, 2, 3, 4, 5] a = [ 0, [ 1, [2, 3], 4 ], 5 ] a.flatten(-2) # => [0, 1, 2, 3, 4, 5] [0, 1, 2].flatten(-1) # => [0, 1, 2]
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_obj_freeze(result);
rb_ary_replace(ary, result);
if (mod) ARY_SET_EMBED_LEN(result, 0);
return ary;
} Заменяет каждый вложенный массив в self элементами из этого массива; возвращает self , если изменения были, nil в противном случае.
С аргументом level - положительным целым числом, рекурсивно разлагает по level уровням:
a = [ 0, [ 1, [2, 3], 4 ], 5 ] a.flatten!(1) # => [0, 1, [2, 3], 4, 5] a = [ 0, [ 1, [2, 3], 4 ], 5 ] a.flatten!(2) # => [0, 1, 2, 3, 4, 5] a = [ 0, [ 1, [2, 3], 4 ], 5 ] a.flatten!(3) # => [0, 1, 2, 3, 4, 5] [0, 1, 2].flatten!(1) # => nil
Без аргумента, с аргументом nil или с отрицательным аргументом level, разлагает все уровни:
a = [ 0, [ 1, [2, 3], 4 ], 5 ] a.flatten! # => [0, 1, 2, 3, 4, 5] [0, 1, 2].flatten! # => nil a = [ 0, [ 1, [2, 3], 4 ], 5 ] a.flatten!(-1) # => [0, 1, 2, 3, 4, 5] a = [ 0, [ 1, [2, 3], 4 ], 5 ] a.flatten!(-2) # => [0, 1, 2, 3, 4, 5] [0, 1, 2].flatten!(-1) # => nil
static VALUE
rb_ary_hash(VALUE ary)
{
long i;
st_index_t h;
VALUE n;
h = rb_hash_start(RARRAY_LEN(ary));
h = rb_hash_uint(h, (st_index_t)rb_ary_hash);
for (i=0; i<RARRAY_LEN(ary); i++) {
n = rb_hash(RARRAY_AREF(ary, i));
h = rb_hash_uint(h, NUM2LONG(n));
}
h = rb_hash_end(h);
return ST2FIX(h);
} Возвращает целое хэш-значение для self.
Два массива с одинаковым содержимым будут иметь одинаковый хэш-код (и сравнятся с помощью eql?):
[0, 1, 2].hash == [0, 1, 2].hash # => true [0, 1, 2].hash == [0, 1, 3].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;
} Возвращает true , если для некоторого индекса i в self, obj == self[i]; в противном случае false:
[0, 1, 2].include?(2) # => true [0, 1, 2].include?(3) # => false
Возвращает индекс указанного элемента.
Если аргумент object задан, но блок нет, возвращает индекс первого элемента element, для которого object == element:
a = [:foo, 'bar', 2, 'bar']
a.index('bar') # => 1
Возвращает nil , если такой элемент не найден.
Если и аргумент object и блок заданы, вызывает блок с каждым последующим элементом; возвращает индекс первого элемента, для которого блок возвращает истинное значение:
a = [:foo, 'bar', 2, 'bar']
a.index {|element| element == 'bar' } # => 1
Возвращает nil , если блок никогда не возвращает истинное значение.
Если ни аргумент, ни блок не заданы, возвращает новый перечислитель:
a = [:foo, 'bar', 2]
e = a.index
e # => #<Enumerator: [:foo, "bar", 2]:index>
e.each {|element| element == 'bar' } # => 1
Array#find_index является псевдонимом для Array#index.
Связанные: rindex.
VALUE
rb_ary_replace(VALUE copy, VALUE orig)
{
rb_ary_modify_check(copy);
orig = to_ary(orig);
if (copy == orig) return copy;
if (RARRAY_LEN(orig) <= RARRAY_EMBED_LEN_MAX) {
VALUE shared_root = 0;
if (ARY_OWNS_HEAP_P(copy)) {
ary_heap_free(copy);
}
else if (ARY_SHARED_P(copy)) {
shared_root = ARY_SHARED_ROOT(copy);
FL_UNSET_SHARED(copy);
}
FL_SET_EMBED(copy);
ary_memcpy(copy, 0, RARRAY_LEN(orig), RARRAY_CONST_PTR_TRANSIENT(orig));
if (shared_root) {
rb_ary_decrement_share(shared_root);
}
ARY_SET_LEN(copy, RARRAY_LEN(orig));
}
else {
VALUE shared_root = ary_make_shared(orig);
if (ARY_OWNS_HEAP_P(copy)) {
ary_heap_free(copy);
}
else {
rb_ary_unshare_safe(copy);
}
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);
}
ary_verify(copy);
return copy;
} Заменяет содержимое self содержимым other_array; возвращает self:
a = [:foo, 'bar', 2] a.replace(['foo', :bar, 3]) # => ["foo", :bar, 3]
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 перед или после элемента с целочисленным индексом offset; возвращает self.
Когда index - неотрицательное значение, вставляет все заданные objects перед элементом со смещением index:
a = [:foo, 'bar', 2] a.insert(1, :bat, :bam) # => [:foo, :bat, :bam, "bar", 2]
Расширяет массив, если index выходит за пределы массива (index >= self.size):
a = [:foo, 'bar', 2] a.insert(5, :bat, :bam) a # => [:foo, "bar", 2, nil, nil, :bat, :bam]
Ничего не делает, если объекты не заданы:
a = [:foo, 'bar', 2] a.insert(1) a.insert(50) a.insert(-50) a # => [:foo, "bar", 2]
Когда index - отрицательное значение, вставляет все заданные objects после элемента со смещением index+self.size:
a = [:foo, 'bar', 2] a.insert(-2, :bat, :bam) a # => [:foo, "bar", :bat, :bam, 2]
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]"
Array#to_s является псевдонимом для Array#inspect.
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;
}
}
ary_recycle_hash(hash);
return result;
} Возвращает true , если массив и other_ary имеют хотя бы один общий элемент, в противном случае возвращает false.
a = [ 1, 2, 3 ] b = [ 3, 4, 5 ] c = [ 5, 6, 7 ] a.intersect?(b) #=> true a.intersect?(c) #=> false
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, так и во всех заданных массивах other_arrays; дубликаты опущены; элементы сравниваются с использованием eql?:
[0, 1, 2, 3].intersection([0, 1, 2], [0, 1, 3]) # => [0, 1] [0, 0, 1, 1, 2, 3].intersection([0, 1, 2], [0, 1, 3]) # => [0, 1]
Сохраняет порядок из self:
[0, 1, 2].intersection([2, 1, 0]) # => [0, 1, 2]
Возвращает копию self, если аргументы не заданы.
Связанный метод: Array#&.
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);
} Возвращает новую строку, образованную путем соединения элементов массива после преобразования. Для каждого элемента element
-
Использует
element.to_s, еслиelementне являетсяkind_of?(Array). -
Использует рекурсивный
element.join(separator), еслиelementявляетсяkind_of?(Array).
Без аргументов соединяет с использованием разделителя выходного поля, $,:
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:
a = [:foo, 'bar', 2, :bam]
a.keep_if {|element| element.to_s.start_with?('b') } # => ["bar", :bam]
Возвращает новый перечислитель, если блок не задан:
a = [:foo, 'bar', 2, :bam] a.keep_if # => #<Enumerator: [:foo, "bar", 2, :bam]:keep_if>
VALUE
rb_ary_last(int argc, const VALUE *argv, VALUE ary)
{
if (argc == 0) {
long len = RARRAY_LEN(ary);
if (len == 0) return Qnil;
return RARRAY_AREF(ary, len-1);
}
else {
return ary_take_first_or_last(argc, argv, ary, ARY_TAKE_LAST);
}
} Возвращает элементы из self; self не изменяется.
Если аргумент не задан, возвращает последний элемент:
a = [:foo, 'bar', 2] a.last # => 2 a # => [:foo, "bar", 2]
Если self пуст, возвращает nil.
Если задан неотрицательный целочисленный аргумент n, возвращает последние n элементов в новом массиве:
a = [:foo, 'bar', 2] a.last(2) # => ["bar", 2]
Если n >= array.size, возвращает все элементы:
a = [:foo, 'bar', 2] a.last(50) # => [:foo, "bar", 2]
Если n == 0, возвращает новый пустой массив:
a = [:foo, 'bar', 2] a.last(0) # []
Связанный метод: first.
static VALUE
rb_ary_length(VALUE ary)
{
long len = RARRAY_LEN(ary);
return LONG2NUM(len);
} Возвращает количество элементов в self.
Вызывает блок, если он задан, для каждого элемента self; возвращает новый массив, элементами которого являются возвращаемые значения из блока:
a = [:foo, 'bar', 2]
a1 = a.map {|element| element.class }
a1 # => [Symbol, String, Integer]
Возвращает новый перечислитель, если блок не задан:
a = [:foo, 'bar', 2] a1 = a.map a1 # => #<Enumerator: [:foo, "bar", 2]:map>
Array#collect является псевдонимом для Array#map.
Вызывает блок, если он задан, для каждого элемента; заменяет элемент возвращаемым значением блока:
a = [:foo, 'bar', 2]
a.map! { |element| element.class } # => [Symbol, String, Integer]
Возвращает новый перечислитель, если блок не задан:
a = [:foo, 'bar', 2] a1 = a.map! a1 # => #<Enumerator: [:foo, "bar", 2]:map!>
Array#collect! является псевдонимом для Array#map!.
static VALUE
rb_ary_max(int argc, VALUE *argv, VALUE ary)
{
struct cmp_opt_data cmp_opt = { 0, 0 };
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 (result == Qundef || 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(cmp_opt, Integer)) {
return ary_max_opt_fixnum(ary, 1, result);
}
else if (STRING_P(result) && CMP_OPTIMIZABLE(cmp_opt, String)) {
return ary_max_opt_string(ary, 1, result);
}
else if (RB_FLOAT_TYPE_P(result) && CMP_OPTIMIZABLE(cmp_opt, Float)) {
return ary_max_opt_float(ary, 1, result);
}
else {
return ary_max_generic(ary, 1, result);
}
}
}
if (result == Qundef) return Qnil;
return result;
} Возвращает один из следующих результатов:
-
Элемент с максимальным значением из
self. -
Новый массив элементов с максимальным значением, выбранных из
self.
Если блок не задан, каждый элемент в self должен отвечать на метод <=> целым числом.
Без аргумента и блока возвращает элемент в self, имеющий максимальное значение по методу <=>:
[0, 1, 2].max # => 2
С целочисленным аргументом n и без блока возвращает новый массив, содержащий не более n элементов, в убывающем порядке по методу <=>:
[0, 1, 2, 3].max(3) # => [3, 2, 1] [0, 1, 2, 3].max(6) # => [3, 2, 1, 0]
Если задан блок, он должен возвращать целое число.
С блоком и без аргумента вызывает блок self.size-1 раз для сравнения элементов; возвращает элемент, имеющий максимальное значение по блоку:
['0', '00', '000'].max {|a, b| a.size <=> b.size } # => "000"
С аргументом n и блоком возвращает новый массив, содержащий не более n элементов, в убывающем порядке по блоку:
['0', '00', '000'].max(2) {|a, b| a.size <=> b.size } # => ["000", "00"]
static VALUE
rb_ary_min(int argc, VALUE *argv, VALUE ary)
{
struct cmp_opt_data cmp_opt = { 0, 0 };
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 (result == Qundef || 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(cmp_opt, Integer)) {
return ary_min_opt_fixnum(ary, 1, result);
}
else if (STRING_P(result) && CMP_OPTIMIZABLE(cmp_opt, String)) {
return ary_min_opt_string(ary, 1, result);
}
else if (RB_FLOAT_TYPE_P(result) && CMP_OPTIMIZABLE(cmp_opt, Float)) {
return ary_min_opt_float(ary, 1, result);
}
else {
return ary_min_generic(ary, 1, result);
}
}
}
if (result == Qundef) return Qnil;
return result;
} Возвращает один из следующих результатов:
-
Элемент с минимальным значением из
self. -
Новый массив элементов с минимальным значением, выбранных из
self.
Если блок не задан, каждый элемент в self должен отвечать на метод <=> целым числом.
Без аргумента и блока возвращает элемент в self, имеющий минимальное значение по методу <=>:
[0, 1, 2].min # => 0
С целочисленным аргументом n и без блока возвращает новый массив, содержащий не более n элементов, в возрастающем порядке по методу <=>:
[0, 1, 2, 3].min(3) # => [0, 1, 2] [0, 1, 2, 3].min(6) # => [0, 1, 2, 3]
Если задан блок, он должен возвращать Integer.
С блоком и без аргумента вызывает блок self.size-1 раз для сравнения элементов; возвращает элемент, имеющий минимальное значение по блоку:
['0', '00', '000'].min { |a, b| a.size <=> b.size } # => "0"
С аргументом n и блоком возвращает новый массив, содержащий не более n элементов, в возрастающем порядке по блоку:
['0', '00', '000'].min(2) {|a, b| a.size <=> b.size } # => ["0", "00"]
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));
} Возвращает новый 2-элементный массив, содержащий минимальное и максимальное значения из self, либо по методу <=>, либо по заданному блоку:.
Если блок не задан, каждый элемент в self должен отвечать на метод <=> целым числом; возвращает новый 2-элементный массив, содержащий минимальное и максимальное значения из self, по методу <=>:
[0, 1, 2].minmax # => [0, 2]
Если задан блок, он должен возвращать целое число; блок вызывается self.size-1 раз для сравнения элементов; возвращает новый 2-элементный массив, содержащий минимальное и максимальное значения из self, по блоку:
['0', '00', '000'].minmax {|a, b| a.size <=> b.size } # => ["0", "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 не удовлетворяет заданному критерию.
Без блока и аргумента, возвращает true, если self не имеет ни одного истинного элемента, и false в противном случае:
[nil, false].none? # => true [nil, 0, false].none? # => false [].none? # => true
С блоком и без аргумента, вызывает блок для каждого элемента в self; возвращает true, если блок не возвращает истинного значения для ни одного элемента, и false в противном случае:
[0, 1, 2].none? {|element| element > 3 } # => true
[0, 1, 2].none? {|element| element > 1 } # => false
Если аргумент obj задан, возвращает true, если obj.=== не имеет ни одного элемента, и false в противном случае:
['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
Связанно с: Enumerable#none?
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
Если аргумент obj задан, возвращает true, если obj.=== имеет ровно один элемент, и 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
Связанно с: Enumerable#one?
# File pack.rb, line 143 def pack(fmt, buffer: nil) Primitive.pack_pack(fmt, buffer) end
Упаковывает содержимое arr в двоичную последовательность в соответствии с инструкциями в aTemplateString (см. таблицу ниже). Директивы «A», «a» и «Z» могут быть дополнены числом, задающим ширину результирующего поля. Остальные директивы также могут принимать число, указывающее количество элементов массива для преобразования. Если число равно звёздочке («*»), будут преобразованы все оставшиеся элементы массива. Любая из директив «sSiIlL» может быть дополнена нижним подчеркиванием («_») или восклицательным знаком («!»), чтобы использовать родной размер платформы для указанного типа; в противном случае используется платформенно-независимый размер. Пробелы в строке шаблона игнорируются. См. также String#unpack.
a = [ "a", "b", "c" ]
n = [ 65, 66, 67 ]
a.pack("A3A3A3") #=> "a b c "
a.pack("a3a3a3") #=> "a\000\000b\000\000c\000\000"
n.pack("ccc") #=> "ABC"
Если aBufferString указан и его ёмкости достаточно, pack использует его в качестве буфера и возвращает его. Когда смещение задано началом aTemplateString, результат заполняется после смещения. Если исходное содержимое aBufferString существует и оно длиннее смещения, остаток offsetOfBuffer перезаписывается результатом. Если оно короче, пробел заполняется «\0».
# packed data is appended by default
[255].pack("C", buffer:"foo".b) #=> "foo\xFF"
# "@0" (offset 0) specifies that packed data is filled from beginning.
# Also, original data after packed data is removed. ("oo" is removed.)
[255].pack("@0C", buffer:"foo".b) #=> "\xFF"
# If the offset is bigger than the original length, \x00 is filled.
[255].pack("@5C", buffer:"foo".b) #=> "foo\x00\x00\xFF"
Обратите внимание, что опция «buffer» не гарантирует отсутствие выделения памяти в pack. Если ёмкость aBufferString недостаточна, pack выделяет память.
Директивы для pack.
Integer | Array |
Directive | Element | Meaning
----------------------------------------------------------------------------
C | Integer | 8-bit unsigned (unsigned char)
S | Integer | 16-bit unsigned, native endian (uint16_t)
L | Integer | 32-bit unsigned, native endian (uint32_t)
Q | Integer | 64-bit unsigned, native endian (uint64_t)
J | Integer | pointer width unsigned, native endian (uintptr_t)
| | (J is available since Ruby 2.3.)
| |
c | Integer | 8-bit signed (signed char)
s | Integer | 16-bit signed, native endian (int16_t)
l | Integer | 32-bit signed, native endian (int32_t)
q | Integer | 64-bit signed, native endian (int64_t)
j | Integer | pointer width signed, native endian (intptr_t)
| | (j is available since Ruby 2.3.)
| |
S_ S! | Integer | unsigned short, native endian
I I_ I! | Integer | unsigned int, native endian
L_ L! | Integer | unsigned long, native endian
Q_ Q! | Integer | unsigned long long, native endian (ArgumentError
| | if the platform has no long long type.)
| | (Q_ and Q! is available since Ruby 2.1.)
J! | Integer | uintptr_t, native endian (same with J)
| | (J! is available since Ruby 2.3.)
| |
s_ s! | Integer | signed short, native endian
i i_ i! | Integer | signed int, native endian
l_ l! | Integer | signed long, native endian
q_ q! | Integer | signed long long, native endian (ArgumentError
| | if the platform has no long long type.)
| | (q_ and q! is available since Ruby 2.1.)
j! | Integer | intptr_t, native endian (same with j)
| | (j! is available since Ruby 2.3.)
| |
S> s> S!> s!> | Integer | same as the directives without ">" except
L> l> L!> l!> | | big endian
I!> i!> | | (available since Ruby 1.9.3)
Q> q> Q!> q!> | | "S>" is the same as "n"
J> j> J!> j!> | | "L>" is the same as "N"
| |
S< s< S!< s!< | Integer | same as the directives without "<" except
L< l< L!< l!< | | little endian
I!< i!< | | (available since Ruby 1.9.3)
Q< q< Q!< q!< | | "S<" is the same as "v"
J< j< J!< j!< | | "L<" is the same as "V"
| |
n | Integer | 16-bit unsigned, network (big-endian) byte order
N | Integer | 32-bit unsigned, network (big-endian) byte order
v | Integer | 16-bit unsigned, VAX (little-endian) byte order
V | Integer | 32-bit unsigned, VAX (little-endian) byte order
| |
U | Integer | UTF-8 character
w | Integer | BER-compressed integer
Float | Array |
Directive | Element | Meaning
---------------------------------------------------------------------------
D d | Float | double-precision, native format
F f | Float | single-precision, native format
E | Float | double-precision, little-endian byte order
e | Float | single-precision, little-endian byte order
G | Float | double-precision, network (big-endian) byte order
g | Float | single-precision, network (big-endian) byte order
String | Array |
Directive | Element | Meaning
---------------------------------------------------------------------------
A | String | arbitrary binary string (space padded, count is width)
a | String | arbitrary binary string (null padded, count is width)
Z | String | same as ``a'', except that null is added with *
B | String | bit string (MSB first)
b | String | bit string (LSB first)
H | String | hex string (high nibble first)
h | String | hex string (low nibble first)
u | String | UU-encoded string
M | String | quoted printable, MIME encoding (see also RFC2045)
| | (text mode but input must use LF and output LF)
m | String | base64 encoded string (see RFC 2045)
| | (if count is 0, no line feed are added, see RFC 4648)
| | (count specifies input bytes between each LF,
| | rounded down to nearest multiple of 3)
P | String | pointer to a structure (fixed-length string)
p | String | pointer to a null-terminated string
Misc. | Array |
Directive | Element | Meaning
---------------------------------------------------------------------------
@ | --- | moves to absolute position
X | --- | back up a byte
x | --- | null byte 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; возвращает self. Порядок перестановок неопределён.
При вызове с блоком и положительным целым аргументом n (0 < n <= self.size) вызывает блок со всеми перестановками кортежей длиной n элементов из self.
Пример:
a = [0, 1, 2]
a.permutation(2) {|permutation| p permutation }
Вывод:
[0, 1] [0, 2] [1, 0] [1, 2] [2, 0] [2, 1]
Другой пример:
a = [0, 1, 2]
a.permutation(3) {|permutation| p permutation }
Вывод:
[0, 1, 2] [0, 2, 1] [1, 0, 2] [1, 2, 0] [2, 0, 1] [2, 1, 0]
Если n равно нулю, вызывает блок один раз с пустым массивом:
a = [0, 1, 2]
a.permutation(0) {|permutation| p permutation }
Вывод:
[]
Если n находится вне диапазона (отрицательное или больше self.size), не вызывает блок:
a = [0, 1, 2]
a.permutation(-1) {|permutation| fail 'Cannot happen' }
a.permutation(4) {|permutation| fail 'Cannot happen' }
При вызове с блоком без аргументов, ведет себя так же, как a.permutation(a.size):
a = [0, 1, 2]
a.permutation {|permutation| p permutation }
Вывод:
[0, 1, 2] [0, 2, 1] [1, 0, 2] [1, 2, 0] [2, 0, 1] [2, 1, 0]
Возвращает новый перечислитель, если блок не задан:
a = [0, 1, 2] a.permutation # => #<Enumerator: [0, 1, 2]:permutation> a.permutation(2) # => #<Enumerator: [0, 1, 2]:permutation(2)>
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 не пуст, удаляет и возвращает последний элемент:
a = [:foo, 'bar', 2] a.pop # => 2 a # => [:foo, "bar"]
Возвращает nil, если массив пуст.
Если задан неотрицательный целочисленный аргумент n и он находится в пределах, удаляет и возвращает последние n элементов в новом массиве:
a = [:foo, 'bar', 2] a.pop(2) # => ["bar", 2]
Если n положительный и выходит за пределы диапазона, удаляет и возвращает все элементы:
a = [:foo, 'bar', 2] a.pop(50) # => [:foo, "bar", 2]
Добавляет заданные objects в начало self:
a = [:foo, 'bar', 2] a.unshift(:bam, :bat) # => [:bam, :bat, :foo, "bar", 2]
Array#prepend — псевдоним для Array#unshift.
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 = tmpary(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, FL_USER5);
rb_yield(subarray);
if (! FL_TEST(t0, FL_USER5)) {
rb_raise(rb_eRuntimeError, "product reentered");
}
else {
FL_UNSET(t0, FL_USER5);
}
}
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:
tmpary_discard(t0);
ALLOCV_END(t1);
return NIL_P(result) ? ary : result;
} Вычисляет и возвращает или генерирует все комбинации элементов из всех массивов, включая как self , так и other_arrays.
-
Количество комбинаций равно произведению размеров всех массивов, включая как
self, так иother_arrays. -
Порядок возвращаемых комбинаций неопределён.
Без блока возвращает комбинации как массив массивов:
a = [0, 1, 2] a1 = [3, 4] a2 = [5, 6] p = a.product(a1) p.size # => 6 # a.size * a1.size p # => [[0, 3], [0, 4], [1, 3], [1, 4], [2, 3], [2, 4]] p = a.product(a1, a2) p.size # => 12 # a.size * a1.size * a2.size p # => [[0, 3, 5], [0, 3, 6], [0, 4, 5], [0, 4, 6], [1, 3, 5], [1, 3, 6], [1, 4, 5], [1, 4, 6], [2, 3, 5], [2, 3, 6], [2, 4, 5], [2, 4, 6]]
Если какой-либо аргумент является пустым массивом, возвращает пустой массив.
Без аргументов возвращает массив из 1-элементных массивов, каждый из которых содержит элемент из self:
a.product # => [[0], [1], [2]]
При заданном блоке генерирует каждую комбинацию как массив; возвращает self:
a.product(a1) {|combination| p combination }
Вывод:
[0, 3] [0, 4] [1, 3] [1, 4] [2, 3] [2, 4]
Если какой-либо аргумент является пустым массивом, блок не вызывается:
a.product(a1, a2, []) {|combination| fail 'Cannot happen' }
Без аргументов генерирует каждый элемент из self как 1-элементный массив:
a.product {|combination| p combination }
Вывод:
[0] [1] [2]
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] a.push(:baz, :bat) # => [:foo, "bar", 2, :baz, :bat]
Добавляет каждый аргумент как отдельный элемент, даже если это другой массив:
a = [:foo, 'bar', 2] a1 = a.push([:baz, :bat], [:bam, :bad]) a1 # => [:foo, "bar", 2, [:baz, :bat], [:bam, :bad]]
Array#append — псевдоним для Array#push.
VALUE
rb_ary_rassoc(VALUE ary, VALUE value)
{
long i;
VALUE v;
for (i = 0; i < RARRAY_LEN(ary); ++i) {
v = 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;
} Возвращает первый элемент в self который является массивом, где второй элемент == obj:
a = [{foo: 0}, [2, 4], [4, 5, 6], [4, 5]]
a.rassoc(4) # => [2, 4]
Возвращает nil если такой элемент не найден.
Связанно с: 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, если блок не задан:
a = [:foo, 'bar', 2] a.reject # => #<Enumerator: [:foo, "bar", 2]:reject>
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 если были удалены какие-либо элементы:
a = [:foo, 'bar', 2, 'bat']
a.reject! {|element| element.to_s.start_with?('b') } # => [:foo, 2]
Возвращает nil если элементы не были удалены.
Возвращает новый объект Enumerator, если блок не задан:
a = [:foo, 'bar', 2] a.reject! # => #<Enumerator: [:foo, "bar", 2]:reject!>
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;
} Вызывает блок для каждой повторяющейся комбинации длины n элементов массива self; каждая комбинация — массив; возвращает self. Порядок комбинаций не определён.
При передаче блока и положительного целого числа n, вызывает блок для каждой повторяющейся комбинации кортежей длины n элементов массива self. Количество комбинаций равно (n+1)(n+2)/2.
n = 1:
a = [0, 1, 2]
a.repeated_combination(1) {|combination| p combination }
Вывод:
[0] [1] [2]
n = 2:
a.repeated_combination(2) {|combination| p combination }
Вывод:
[0, 0] [0, 1] [0, 2] [1, 1] [1, 2] [2, 2]
Если n равно нулю, вызывает блок один раз с пустым массивом.
Если n отрицательно, блок не вызывается:
a.repeated_combination(-1) {|combination| fail 'Cannot happen' }
Возвращает новый объект Enumerator, если блок не задан:
a = [0, 1, 2] a.repeated_combination(2) # => #<Enumerator: [0, 1, 2]:combination(2)>
Используя Enumerator, удобно показать комбинации и их количества для некоторых значений n:
e = a.repeated_combination(0) e.size # => 1 e.to_a # => [[]] e = a.repeated_combination(1) e.size # => 3 e.to_a # => [[0], [1], [2]] e = a.repeated_combination(2) e.size # => 6 e.to_a # => [[0, 0], [0, 1], [0, 2], [1, 1], [1, 2], [2, 2]]
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;
} Вызывает блок для каждой повторяющейся перестановки длины n элементов массива self; каждая перестановка — массив; возвращает self. Порядок перестановок не определён.
При передаче блока и положительного целого числа n, вызывает блок для каждой повторяющейся перестановки кортежей длины n элементов массива self. Количество перестановок равно self.size**n.
n = 1:
a = [0, 1, 2]
a.repeated_permutation(1) {|permutation| p permutation }
Вывод:
[0] [1] [2]
n = 2:
a.repeated_permutation(2) {|permutation| p permutation }
Вывод:
[0, 0] [0, 1] [0, 2] [1, 0] [1, 1] [1, 2] [2, 0] [2, 1] [2, 2]
Если n равно нулю, вызывает блок один раз с пустым массивом.
Если n отрицательно, блок не вызывается:
a.repeated_permutation(-1) {|permutation| fail 'Cannot happen' }
Возвращает новый объект Enumerator, если блок не задан:
a = [0, 1, 2] a.repeated_permutation(2) # => #<Enumerator: [0, 1, 2]:permutation(2)>
Используя Enumerator, удобно показать перестановки и их количества для некоторых значений n:
e = a.repeated_permutation(0) e.size # => 1 e.to_a # => [[]] e = a.repeated_permutation(1) e.size # => 3 e.to_a # => [[0], [1], [2]] e = a.repeated_permutation(2) e.size # => 9 e.to_a # => [[0, 0], [0, 1], [0, 2], [1, 0], [1, 1], [1, 2], [2, 0], [2, 1], [2, 2]]
Заменяет содержимое self содержимым other_array; возвращает self:
a = [:foo, 'bar', 2] a.replace(['foo', :bar, 3]) # => ["foo", :bar, 3]
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_TRANSIENT(ary);
VALUE *p2 = (VALUE *)RARRAY_CONST_PTR_TRANSIENT(dup) + len - 1;
do *p2-- = *p1++; while (--len > 0);
}
ARY_SET_LEN(dup, RARRAY_LEN(ary));
return dup;
} Возвращает новый массив с элементами self в обратном порядке.
a = ['foo', 'bar', 'two'] a1 = a.reverse a1 # => ["two", "bar", "foo"]
static VALUE
rb_ary_reverse_bang(VALUE ary)
{
return rb_ary_reverse(ary);
} Инвертирует self на месте:
a = ['foo', 'bar', 'two'] a.reverse! # => ["two", "bar", "foo"]
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:
a = [:foo, 'bar', 2]
a.reverse_each {|element| puts "#{element.class} #{element}" }
Вывод:
Integer 2 String bar Symbol foo
Позволяет изменять массив во время итерации:
a = [:foo, 'bar', 2]
a.reverse_each {|element| puts element; a.clear if element.to_s.start_with?('b') }
Вывод:
2 bar
При отсутствии блока возвращает новый объект Enumerator:
a = [:foo, 'bar', 2]
e = a.reverse_each
e # => #<Enumerator: [:foo, "bar", 2]:reverse_each>
a1 = e.each {|element| puts "#{element.class} #{element}" }
Вывод:
Integer 2 String bar Symbol foo
Связанно с: each, each_index.
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:
a = [:foo, 'bar', 2, 'bar']
e = a.rindex
e # => #<Enumerator: [:foo, "bar", 2, "bar"]:rindex>
e.each {|element| element == 'bar' } # => 3
Связанно с: index.
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_TRANSIENT(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 с элементами, повернутыми с одного конца на другой.
При отсутствии аргумента возвращает новый массив, похожий на self, за исключением того, что первый элемент был повернут на последнюю позицию:
a = [:foo, 'bar', 2, 'bar'] a1 = a.rotate a1 # => ["bar", 2, "bar", :foo]
При передаче неотрицательного целого числа count, возвращает новый массив с count элементами, повернутыми от начала к концу:
a = [:foo, 'bar', 2] a1 = a.rotate(2) a1 # => [2, :foo, "bar"]
Если count велико, используется count % array.size как значение:
a = [:foo, 'bar', 2] a1 = a.rotate(20) a1 # => [2, :foo, "bar"]
Если count равно нулю, возвращает копию self, без изменений:
a = [:foo, 'bar', 2] a1 = a.rotate(0) a1 # => [:foo, "bar", 2]
При передаче отрицательного целого числа count, вращение происходит в обратном направлении, с конца к началу:
a = [:foo, 'bar', 2] a1 = a.rotate(-2) a1 # => ["bar", 2, :foo]
Если count мало (далеко от нуля), используется count % array.size как значение:
a = [:foo, 'bar', 2] a1 = a.rotate(-5) a1 # => ["bar", 2, :foo]
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.
Если аргумент не указан, перемещает первый элемент в последнюю позицию:
a = [:foo, 'bar', 2, 'bar'] a.rotate! # => ["bar", 2, "bar", :foo]
Если задан неотрицательное целое число count, поворачивает count элементов с начала на конец:
a = [:foo, 'bar', 2] a.rotate!(2) a # => [2, :foo, "bar"]
Если count велико, использует count % array.size в качестве значения count:
a = [:foo, 'bar', 2] a.rotate!(20) a # => [2, :foo, "bar"]
Если count равно нулю, возвращает self без изменений:
a = [:foo, 'bar', 2] a.rotate!(0) a # => [:foo, "bar", 2]
Если задано отрицательное Integer count, вращение происходит в противоположном направлении, с конца в начало:
a = [:foo, 'bar', 2] a.rotate!(-2) a # => ["bar", 2, :foo]
Если count мало (далеко от нуля), использует count % array.size в качестве значения count:
a = [:foo, 'bar', 2] a.rotate!(-5) a # => ["bar", 2, :foo]
# File array.rb, line 60
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.
Если аргументов нет, возвращает случайный элемент из self:
a = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] a.sample # => 3 a.sample # => 8
Если self пусто, возвращает nil.
Если задан аргумент n, возвращает новый массив, содержащий n случайных элементов из self:
a.sample(3) # => [8, 9, 2] a.sample(6) # => [9, 6, 10, 3, 1, 4]
Возвращает не более a.size элементов (потому что новые дубликаты не вводятся):
a.sample(a.size * 2) # => [6, 4, 1, 8, 5, 9, 10, 2, 3, 7]
Но self может содержать дубликаты:
a = [1, 1, 1, 2, 2, 3] a.sample(a.size * 2) # => [1, 1, 3, 2, 1, 2]
Аргумент n должен быть неотрицательным числовым значением. Порядок в результирующем массиве не связан с порядком в self. Возвращает новый пустой массив, если self пустой.
Необязательный аргумент 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]
a1 = a.select {|element| element.to_s.start_with?('b') }
a1 # => ["bar", :bam]
Возвращает новый перечислитель, если блок не задан:
a = [:foo, 'bar', 2, :bam] a.select # => #<Enumerator: [:foo, "bar", 2, :bam]:select>
Array#filter является псевдонимом для Array#select.
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, если элементы не были удалены.
Возвращает новый перечислитель, если блок не задан:
a = [:foo, 'bar', 2, :bam] a.select! # => #<Enumerator: [:foo, "bar", 2, :bam]:select!>
Array#filter! является псевдонимом для Array#select!.
# File lib/shellwords.rb, line 237 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;
} Удаляет и возвращает ведущие элементы.
Если аргумент не задан, удаляет и возвращает первый элемент:
a = [:foo, 'bar', 2] a.shift # => :foo a # => ['bar', 2]
Возвращает nil, если self пустой.
Если задан положительное целое число n, удаляет первые n элементы; возвращает эти элементы в новом массиве:
a = [:foo, 'bar', 2] a.shift(2) # => [:foo, 'bar'] a # => [2]
Если n столь же велико, или больше, чем self.length, удаляет все элементы; возвращает эти элементы в новом массиве:
a = [:foo, 'bar', 2] a.shift(3) # => [:foo, 'bar', 2]
Если n равно нулю, возвращает новый пустой массив; self остается без изменений.
# File array.rb, line 26 def shuffle(random: Random) Primitive.rb_ary_shuffle(random) end
Возвращает новый массив с перемешанными элементами self.
a = [1, 2, 3] #=> [1, 2, 3] a.shuffle #=> [2, 3, 1] a #=> [1, 2, 3]
Необязательный аргумент random будет использован в качестве генератора случайных чисел:
a.shuffle(random: Random.new(1)) #=> [1, 3, 2]
# File array.rb, line 12 def shuffle!(random: Random) Primitive.rb_ary_shuffle_bang(random) end
Перемешивает элементы self на месте.
a = [1, 2, 3] #=> [1, 2, 3] a.shuffle! #=> [2, 3, 1] a #=> [2, 3, 1]
Необязательный аргумент random будет использован в качестве генератора случайных чисел:
a.shuffle!(random: Random.new(1)) #=> [1, 3, 2]
Возвращает элементы из self; не изменяет self.
Когда задан единственный целочисленный аргумент 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.
Когда заданы два целочисленных аргумента 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, возвращает массив Array элементов, соответствующих индексам, сгенерированным последовательностью.
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]
Array#slice является псевдонимом для Array#[].
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.
Когда единственным аргументом является целое число n, удаляет и возвращает n-ый элемент в self:
a = [:foo, 'bar', 2] a.slice!(1) # => "bar" a # => [:foo, 2]
Если n отрицательный, счёт ведётся от конца self:
a = [:foo, 'bar', 2] a.slice!(-1) # => 2 a # => [:foo, "bar"]
Если n выходит за пределы диапазона, возвращает nil.
Когда единственными аргументами являются целые числа start и length, удаляет length элементов из self, начиная со смещения start; возвращает удалённые объекты в новом массиве:
a = [:foo, 'bar', 2] a.slice!(0, 2) # => [:foo, "bar"] a # => [2]
Если start + length превышает размер массива, удаляет и возвращает все элементы от смещения start до конца:
a = [:foo, 'bar', 2] a.slice!(1, 50) # => ["bar", 2] a # => [:foo]
Если start == a.size и length неотрицательные, возвращает новый пустой массив.
Если length отрицательный, возвращает nil.
Когда единственным аргументом является объект Range range, интерпретирует range.min как start выше, а range.size как length выше:
a = [:foo, 'bar', 2] a.slice!(1..2) # => ["bar", 2] a # => [:foo]
Если range.start == a.size, возвращает новый пустой массив.
Если range.start больше размера массива, возвращает nil.
Если range.end отрицательный, считает элементы от конца массива:
a = [:foo, 'bar', 2] a.slice!(0..-2) # => [:foo, "bar"] a # => [2]
Если range.start отрицательный, вычисляет начальный индекс, отсчитывая с конца массива:
a = [:foo, 'bar', 2] a.slice!(-2..2) # => ["bar", 2] a # => [:foo]
VALUE
rb_ary_sort(VALUE ary)
{
ary = rb_ary_dup(ary);
rb_ary_sort_bang(ary);
return ary;
} Возвращает новый массив, элементы которого взяты из self, отсортированные.
Без блока сравнивает элементы с использованием оператора <=> (см. Comparable):
a = 'abcde'.split('').shuffle
a # => ["e", "b", "d", "a", "c"]
a1 = a.sort
a1 # => ["a", "b", "c", "d", "e"]
С блоком вызывает блок с каждой парой элементов; для каждой пары элементов a и b, блок должен возвращать целое число:
-
Отрицательное, когда
bдолжен следовать заa. -
Ноль, когда
aиbэквивалентны. -
Положительное, когда
aдолжен следовать заb.
Пример:
a = 'abcde'.split('').shuffle
a # => ["e", "b", "d", "a", "c"]
a1 = a.sort {|a, b| a <=> b }
a1 # => ["a", "b", "c", "d", "e"]
a2 = a.sort {|a, b| b <=> a }
a2 # => ["e", "d", "c", "b", "a"]
Когда блок возвращает ноль, порядок a и b неопределён и может быть неустойчивым:
a = 'abcde'.split('').shuffle
a # => ["e", "b", "d", "a", "c"]
a1 = a.sort {|a, b| 0 }
a1 # => ["c", "e", "b", "d", "a"]
Связанно с: Enumerable#sort_by.
VALUE
rb_ary_sort_bang(VALUE ary)
{
rb_ary_modify(ary);
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;
data.cmp_opt.opt_methods = 0;
data.cmp_opt.opt_inited = 0;
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);
}
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 {
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_UNSET(tmp, FL_FREEZE);
FL_SET_EMBED(tmp);
ARY_SET_EMBED_LEN(tmp, 0);
FL_SET(tmp, FL_FREEZE);
}
/* tmp will be GC'ed. */
RBASIC_SET_CLASS_RAW(tmp, rb_cArray); /* rb_cArray must be marked */
}
ary_verify(ary);
return ary;
} Возвращает self с отсортированными в нём элементами.
Без блока сравнивает элементы с использованием оператора <=> (см. Comparable):
a = 'abcde'.split('').shuffle
a # => ["e", "b", "d", "a", "c"]
a.sort!
a # => ["a", "b", "c", "d", "e"]
С блоком вызывает блок с каждой парой элементов; для каждой пары элементов a и b, блок должен возвращать целое число:
-
Отрицательное, когда
bдолжен следовать заa. -
Ноль, когда
aиbэквивалентны. -
Положительное, когда
aдолжен следовать заb.
Пример:
a = 'abcde'.split('').shuffle
a # => ["e", "b", "d", "a", "c"]
a.sort! {|a, b| a <=> b }
a # => ["a", "b", "c", "d", "e"]
a.sort! {|a, b| b <=> a }
a # => ["e", "d", "c", "b", "a"]
Когда блок возвращает ноль, порядок a и b неопределён и может быть неустойчивым:
a = 'abcde'.split('').shuffle
a # => ["e", "b", "d", "a", "c"]
a.sort! {|a, b| 0 }
a # => ["d", "e", "c", "a", "b"]
static VALUE
rb_ary_sort_by_bang(VALUE ary)
{
VALUE sorted;
RETURN_SIZED_ENUMERATOR(ary, 0, 0, ary_enum_length);
rb_ary_modify(ary);
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"]
Возвращает новый перечислитель, если блок не указан:
a = ['aaaa', 'bbb', 'cc', 'd'] a.sort_by! # => #<Enumerator: ["aaaa", "bbb", "cc", "d"]:sort_by!>
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;
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 (r == Qundef)
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;
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;
} Без блока возвращает объект, эквивалентный:
sum = init
array.each {|element| sum += element }
sum
Например, [e1, e2, e3].sum возвращает init + e1 + e2 + e3.
Примеры:
a = [0, 1, 2, 3] a.sum # => 6 a.sum(100) # => 106
Элементы необязательно должны быть числовыми, но должны быть совместимы друг с другом и с init:
a = ['abc', 'def', 'ghi']
a.sum('jkl') # => "jklabcdefghi"
Когда задан блок, он вызывается с каждым элементом, а возвращаемое значение блока (вместо самого элемента) используется как слагаемое:
a = ['zero', 1, :two]
s = a.sum('Coerced and concatenated: ') {|element| element.to_s }
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);
} Возвращает новый массив, содержащий первые n элемента массива self, где n — неотрицательное целое число; не изменяет self.
Примеры:
a = [0, 1, 2, 3, 4, 5] a.take(1) # => [0] a.take(2) # => [0, 1] a.take(50) # => [0, 1, 2, 3, 4, 5] a # => [0, 1, 2, 3, 4, 5]
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));
} Возвращает новый массив, содержащий ноль или более ведущих элементов массива; не изменяет исходный массив.
При использовании блока, блок вызывается для каждого последующего элемента массива; выполнение останавливается, если блок возвращает ложное значение или nil; возвращает новый Array, содержащий те элементы, для которых блок возвратил истинное значение:
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 # => [0, 1, 2, 3, 4, 5]
Без блока возвращает новый перечислитель:
[0, 1].take_while # => #<Enumerator: [0, 1]:take_while>
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 является экземпляром массива, возвращает self:
a = [:foo, 'bar', 2] a.to_a # => [:foo, "bar", 2]
В противном случае возвращает новый массив, содержащий элементы self:
class MyArray < Array; end a = MyArray.new(['foo', 'bar', 'two']) a.instance_of?(Array) # => false a.kind_of?(Array) # => true a1 = a.to_a a1 # => ["foo", "bar", "two"] a1.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.
При использовании блока, блок вызывается для каждого элемента массива; блок должен вернуть массив из двух элементов, которые образуют пару ключ-значение в возвращаемом хэше:
a = ['foo', :bar, 1, [2, 3], {baz: 4}]
h = a.to_h {|item| [item, item] }
h # => {"foo"=>"foo", :bar=>:bar, 1=>1, [2, 3]=>[2, 3], {:baz=>4}=>{:baz=>4}}
Без блока self должен быть массивом из подмассивов по два элемента, каждый подмассив преобразуется в пару ключ-значение в новом хэше:
[].to_h # => {}
a = [['foo', 'zero'], ['bar', 'one'], ['baz', 'two']]
h = a.to_h
h # => {"foo"=>"zero", "bar"=>"one", "baz"=>"two"}
Возвращает новую строку, сформированную путём вызова метода #inspect для каждого элемента массива:
a = [:foo, 'bar', 2] a.inspect # => "[:foo, \"bar\", 2]"
Array#to_s является псевдонимом для Array#inspect.
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;
} Транспонирует строки и столбцы в массиве массивов; вложенные массивы должны иметь одинаковый размер:
a = [[:a0, :a1], [:b0, :b1], [:c0, :c1]] a.transpose # => [[:a0, :b0, :c0], [:a1, :b1, :c1]]
static VALUE
rb_ary_union_multi(int argc, VALUE *argv, VALUE ary)
{
int i;
long sum;
VALUE hash, ary_union;
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) {
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]);
ary_union = rb_hash_values(hash);
ary_recycle_hash(hash);
return ary_union;
} Возвращает новый массив, являющийся объединением исходного массива и всех переданных массивов; дубликаты удаляются; порядок сохраняется; элементы сравниваются с помощью 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] [0, 1, 2, 3].union([3, 2], [1, 0]) # => [0, 1, 2, 3]
Возвращает копию исходного массива, если аргументов нет.
Связанно с: Array#|.
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);
}
if (hash) {
ary_recycle_hash(hash);
}
return uniq;
} Возвращает новый массив, содержащий элементы исходного массива, не являющиеся дубликатами; сохраняется первое вхождение каждого элемента.
Без блока, дубликаты определяются и удаляются с помощью метода 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) && !ARY_EMBED_P(ary)) {
rb_ary_unshare(ary);
FL_SET_EMBED(ary);
}
ary_resize_capa(ary, hash_size);
rb_hash_foreach(hash, push_value, ary);
ary_recycle_hash(hash);
return ary;
} Удаляет дублирующие элементы из массива; сохраняется первое вхождение; возвращает массив, если элементы были удалены; иначе возвращает nil.
Без блока, элементы определяются и удаляются с помощью метода eql? для сравнения.
Возвращает массив, если элементы были удалены:
a = [0, 0, 1, 1, 2, 2] a.uniq! # => [0, 1, 2]
Возвращает nil, если элементы не были удалены.
С блоком, блок вызывается для каждого элемента; дубликаты определяются (с помощью метода eql?) и удаляются, то есть элементы, для которых блок возвращает одинаковое значение.
Возвращает массив, если элементы были удалены:
a = ['a', 'aa', 'aaa', 'b', 'bb', 'bbb']
a.uniq! {|element| element.size } # => ['a', 'aa', 'aaa']
Возвращает nil, если элементы не были удалены.
static 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;
} Добавляет указанные элементы в начало массива:
a = [:foo, 'bar', 2] a.unshift(:bam, :bat) # => [:bam, :bat, :foo, "bar", 2]
Array#prepend является псевдонимом для Array#unshift.
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;
} Возвращает новый массив, элементами которого являются элементы исходного массива по заданным индексам (целые числа или диапазоны):
Для каждого положительного индекса возвращается элемент по этому смещению:
a = [:foo, 'bar', 2] a.values_at(0, 2) # => [:foo, 2] a.values_at(0..1) # => [:foo, "bar"]
Заданные индексы могут быть в любом порядке и повторяться:
a = [:foo, 'bar', 2] a.values_at(2, 0, 1, 0, 2) # => [2, :foo, "bar", :foo, 2] a.values_at(1, 0..2) # => ["bar", :foo, "bar", 2]
Присваивает nil для индекса, выходящего за пределы массива:
a = [:foo, 'bar', 2] a.values_at(0, 3, 1, 3) # => [:foo, nil, "bar", nil]
Возвращает пустой массив, если аргументов нет.
Для каждого отрицательного индекса отсчёт ведётся от конца массива:
a = [:foo, 'bar', 2] a.values_at(-1, -3) # => [2, :foo]
Присваивает nil для индекса, выходящего за пределы массива:
a = [:foo, 'bar', 2] a.values_at(0, -5, 1, -6, 2) # => [:foo, nil, "bar", nil, 2]
Заданные индексы могут содержать смесь знаков:
a = [:foo, 'bar', 2] a.values_at(0, -2, 1, -1) # => [:foo, "bar", "bar", 2]
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;
} Без блока возвращает новый массив new_array размера self.size , элементами которого являются массивы.
Каждый вложенный массив new_array[n] имеет размер other_arrays.size+1, и содержит:
-
n-ый элемент исходного массива.
-
n-ый элемент каждого из переданных массивов.
Если все массивы имеют одинаковый размер:
a = [:a0, :a1, :a2, :a3] b = [:b0, :b1, :b2, :b3] c = [:c0, :c1, :c2, :c3] d = a.zip(b, c) d # => [[:a0, :b0, :c0], [:a1, :b1, :c1], [:a2, :b2, :c2], [:a3, :b3, :c3]]
Если любой массив в списке короче исходного массива, заполняется nil:
a = [:a0, :a1, :a2, :a3] b = [:b0, :b1, :b2] c = [:c0, :c1] d = a.zip(b, c) d # => [[:a0, :b0, :c0], [:a1, :b1, :c1], [:a2, :b2, nil], [:a3, nil, nil]]
Если любой массив в списке длиннее исходного массива, его хвостовые элементы игнорируются:
a = [:a0, :a1, :a2, :a3] b = [:b0, :b1, :b2, :b3, :b4] c = [:c0, :c1, :c2, :c3, :c4, :c5] d = a.zip(b, c) d # => [[:a0, :b0, :c0], [:a1, :b1, :c1], [:a2, :b2, :c2], [:a3, :b3, :c3]]
При использовании блока, блок вызывается для каждого из подмассивов (формируемых как описано выше); возвращается nil
a = [:a0, :a1, :a2, :a3]
b = [:b0, :b1, :b2, :b3]
c = [:c0, :c1, :c2, :c3]
a.zip(b, c) {|sub_array| p sub_array} # => nil
Вывод:
[:a0, :b0, :c0] [:a1, :b1, :c1] [:a2, :b2, :c2] [:a3, :b3, :c3]
static VALUE
rb_ary_or(VALUE ary1, VALUE ary2)
{
VALUE hash, ary3;
ary2 = to_ary(ary2);
if (RARRAY_LEN(ary1) + RARRAY_LEN(ary2) <= SMALL_ARRAY_LEN) {
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);
ary3 = rb_hash_values(hash);
ary_recycle_hash(hash);
return ary3;
} Возвращает объединение array и массива 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]
Связанно с: Array#union.
Ruby Core © 1993–2022 Yukihiro Matsumoto
Licensed under the Ruby License.
Ruby Standard Library © contributors
Licensed under their own licenses.