класс Array
Массивы — упорядоченные коллекции целых индексов любого объекта.
Array индексация начинается с 0, как в C или Java. Отрицательный индекс предполагается относительным к концу массива — то есть, индекс -1 указывает на последний элемент массива, -2 — на предпоследний элемент массива и так далее.
Создание массивов
Новый массив можно создать, используя литеральный конструктор []. Массивы могут содержать различные типы объектов. Например, массив ниже содержит Integer, String и Float:
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]
Получение информации об Array
Массивы постоянно отслеживают свою длину. Чтобы запросить у массива количество содержащихся в нём элементов, используйте 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]
Удаление элементов из Array
Метод 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]
Выбор элементов из Array
Элементы можно выбирать из массива в соответствии с критериями, определёнными в блоке. Выбор может происходить в разрушающем или неразрушающем способе. В то время как разрушающие операции изменят массив, на котором они были вызваны, неразрушающие методы обычно возвращают новый массив с выбранными элементами, но оставляют исходный массив неизменным.
Неразрушающий выбор
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]
для 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;
} Возвращает новый массив.
В первом случае, если не отправлять аргументы, новый массив будет пустым. Когда отправляется size и необязательный default , создаётся массив с size копиями default. Обратите внимание, что все элементы будут ссылаться на один и тот же объект default.
Второй вариант создаёт копию переданного массива (массив генерируется путём вызова to_ary на параметре).
first_array = ["Matz", "Guido"] second_array = Array.new(first_array) #=> ["Matz", "Guido"] first_array.equal? second_array #=> false
В последнем случае создаётся массив заданного размера. Каждый элемент в этом массиве создаётся путём передачи индекса элемента в предоставленный блок и сохранения возвращаемого значения.
Array.new(3) {|index| index ** 2}
# => [0, 1, 4]
Общие ошибки
При отправке второго параметра один и тот же объект будет использоваться в качестве значения для всех элементов массива:
a = Array.new(2, Hash.new)
# => [{}, {}]
a[0]['cat'] = 'feline'
a # => [{"cat"=>"feline"}, {"cat"=>"feline"}]
a[1]['cat'] = 'Felix'
a # => [{"cat"=>"Felix"}, {"cat"=>"Felix"}]
Поскольку все элементы Array хранят один и тот же хэш, изменения в одном из них повлияют на все.
Если вам нужны отдельные копии, используйте версию с блоком, которая каждый раз использует результат этого блока для инициализации элемента массива:
a = Array.new(2) {Hash.new}
a[0]['cat'] = 'feline'
a # => [{"cat"=>"feline"}, {}]
static VALUE
rb_ary_s_try_convert(VALUE dummy, VALUE ary)
{
return rb_check_array_type(ary);
} Пытается преобразовать obj в массив, используя метод to_ary. Возвращает преобразованный массив или nil, если obj не может быть преобразован. Этот метод можно использовать для проверки, является ли аргумент массивом.
Array.try_convert([1]) #=> [1]
Array.try_convert("1") #=> nil
if tmp = Array.try_convert(arg)
# the argument is an array
elsif tmp = String.try_convert(arg)
# the argument is a string
end
Общедоступные методы экземпляров
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;
} Set Пересечение — Возвращает новый массив, содержащий уникальные элементы, общие для двух массивов. Порядок элементов сохраняется из исходного массива.
Для повышения эффективности сравнение элементов выполняется с использованием методов hash и eql?.
[ 1, 1, 3, 5 ] & [ 3, 2, 1 ] #=> [ 1, 3 ] [ 'a', 'b', 'b', 'z' ] & [ 'a', 'b', 'c' ] #=> [ 'a', 'b' ]
См. также Array#uniq.
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_obj_class(ary), 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_obj_class(ary), 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;
} Повторение — С аргументом типа String, эквивалентно ary.join(str).
В противном случае возвращает новый массив, созданный путём конкатенации int копий self.
[ 1, 2, 3 ] * 3 #=> [ 1, 2, 3, 1, 2, 3, 1, 2, 3 ] [ 1, 2, 3 ] * "," #=> "1,2,3"
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;
} Конкатенация — Возвращает новый массив, созданный путём конкатенации двух массивов.
[ 1, 2, 3 ] + [ 4, 5 ] #=> [ 1, 2, 3, 4, 5 ] a = [ "a", "b", "c" ] c = a + [ "d", "e", "f" ] c #=> [ "a", "b", "c", "d", "e", "f" ] a #=> [ "a", "b", "c" ]
Обратите внимание, что
x += y
то же самое, что
x = x + y
Это означает, что он создаёт новый массив. Вследствие этого многократное применение += к массивам может быть довольно неэффективным.
См. также Array#concat.
static VALUE
rb_ary_diff(VALUE ary1, VALUE ary2)
{
VALUE ary3;
VALUE hash;
long i;
ary2 = to_ary(ary2);
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_ary. Порядок элементов сохраняется из исходного массива.
Для повышения эффективности сравнение элементов выполняется с использованием методов hash и eql?.
[ 1, 1, 2, 2, 3, 3, 4, 5 ] - [ 1, 2, 4 ] #=> [ 3, 3, 5 ]
Обратите внимание, что, хотя 1 и 2 присутствовали только один раз в аргументе массива, и дважды в массиве получателя, все вхождения каждого Integer удаляются в возвращаемом массиве.
Если вам требуется поведение, подобное множествам, обратитесь к классу библиотеки Set.
См. также 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;
} Добавление — Добавляет указанный объект в конец этого массива. Это выражение возвращает сам массив, поэтому несколько добавлений можно цепочить.
a = [ 1, 2 ]
a << "c" << "d" << [ 3, 4 ]
#=> [ 1, 2, "c", "d", [ 3, 4 ] ]
a
#=> [ 1, 2, "c", "d", [ 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) если этот массив меньше, равен или больше other_ary.
Каждый объект в каждом массиве сравнивается (с использованием оператора <=>).
Массивы сравниваются по «элементному» принципу; первый элемент ary сравнивается с первым элементом other_ary с использованием оператора <=>, затем каждый из вторых элементов и т. д… Как только результат любого такого сравнения отличен от нуля (т. е. два соответствующих элемента не равны), этот результат возвращается для всего сравнения массивов.
Если все элементы равны, то результат основан на сравнении длин массивов. Таким образом, два массива «равны» согласно Array#<=> тогда и только тогда, когда они имеют одинаковую длину, и значение каждого элемента равно значению соответствующего элемента в другом массиве.
Возвращается nil, если other_ary не является массивом или если сравнение двух элементов вернуло nil.
[ "a", "a", "c" ] <=> [ "a", "b", "c" ] #=> -1 [ 1, 2, 3, 4, 5, 6 ] <=> [ 1, 2 ] #=> +1 [ 1, 2 ] <=> [ 1, :two ] #=> nil
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);
} Равенство — Два массива равны, если они содержат одинаковое количество элементов и если каждый элемент равен (согласно Object#==) соответствующему элементу в other_ary.
[ "a", "c" ] == [ "a", "c", 7 ] #=> false [ "a", "c", 7 ] == [ "a", "c", 7 ] #=> true [ "a", "c", 7 ] == [ "a", "d", "f" ] #=> false
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]);
} Ссылка на элемент — Возвращает элемент по index, или возвращает подмассив, начинающийся с start индекса и продолжающийся length элементами, или возвращает подмассив, заданный range индексами.
Отрицательные индексы считаются назад от конца массива (-1 — последний элемент). Для случаев start и range начальный индекс находится перед элементом. Кроме того, пустой массив возвращается, когда начальный индекс диапазона элементов находится в конце массива.
Возвращает nil если индекс (или начальный индекс) выходит за пределы диапазона.
a = [ "a", "b", "c", "d", "e" ] a[2] + a[0] + a[1] #=> "cab" a[6] #=> nil a[1, 2] #=> [ "b", "c" ] a[1..3] #=> [ "b", "c", "d" ] a[4..7] #=> [ "e" ] a[6..10] #=> nil a[-3, 3] #=> [ "c", "d", "e" ] # special cases a[5] #=> nil a[6, 1] #=> nil a[5, 1] #=> [] a[5..10] #=> []
static VALUE
rb_ary_aset(int argc, VALUE *argv, VALUE ary)
{
long offset, beg, len;
VALUE rpl;
if (argc == 3) {
rb_ary_modify_check(ary);
beg = NUM2LONG(argv[0]);
len = NUM2LONG(argv[1]);
goto range;
}
rb_check_arity(argc, 2, 2);
rb_ary_modify_check(ary);
if (FIXNUM_P(argv[0])) {
offset = FIX2LONG(argv[0]);
goto fixnum;
}
if (rb_range_beg_len(argv[0], &beg, &len, RARRAY_LEN(ary), 1)) {
/* check if idx is Range */
range:
rpl = rb_ary_to_ary(argv[argc-1]);
rb_ary_splice(ary, beg, len, RARRAY_CONST_PTR_TRANSIENT(rpl), RARRAY_LEN(rpl));
RB_GC_GUARD(rpl);
return argv[argc-1];
}
offset = NUM2LONG(argv[0]);
fixnum:
rb_ary_store(ary, offset, argv[1]);
return argv[1];
} Присваивание элемента — Устанавливает элемент по index, или заменяет подмассив, начиная с start индекса на length элементов, или заменяет подмассив, заданный range индексами.
Если индексы больше текущей ёмкости массива, массив автоматически увеличивается. Элементы вставляются в массив по start, если length равно нулю.
Отрицательные индексы будут отсчитываться назад от конца массива. Для случаев start и range начальный индекс находится перед элементом.
Возникает IndexError, если отрицательный индекс указывает на позицию до начала массива.
См. также Array#push и Array#unshift.
a = Array.new a[4] = "4"; #=> [nil, nil, nil, nil, "4"] a[0, 3] = [ 'a', 'b', 'c' ] #=> ["a", "b", "c", nil, "4"] a[1..2] = [ 1, 2 ] #=> ["a", 1, 2, nil, "4"] a[0, 2] = "?" #=> ["?", 2, nil, "4"] a[0..2] = "A" #=> ["A", "4"] a[-1] = "Z" #=> ["A", "Z"] a[1..-1] = nil #=> ["A", nil] a[1..-1] = [] #=> ["A"] a[0, 0] = [ 1, 2 ] #=> [1, 2, "A"] a[3, 0] = "B" #=> [1, 2, "A", "B"]
# 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;
} См. также 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;
} См. также Enumerable#any?
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;
} Ищет в массиве, элементы которого также являются массивами, сравнивая obj с первым элементом каждого вложенного массива с использованием obj.==.
Возвращает первый вложенный массив, который соответствует условию (т. е. первый связанный массив), или nil если совпадений не найдено.
См. также Array#rassoc
s1 = [ "colors", "red", "blue", "green" ]
s2 = [ "letters", "a", "b", "c" ]
s3 = "foo"
a = [ s1, s2, s3 ]
a.assoc("letters") #=> [ "letters", "a", "b", "c" ]
a.assoc("foo") #=> nil
VALUE
rb_ary_at(VALUE ary, VALUE pos)
{
return rb_ary_entry(ary, NUM2LONG(pos));
} Возвращает элемент по указанному <index>. Отрицательный индекс считает с конца <self>. Возвращает nil если индекс вне диапазона. См. также Array#[].
a = [ "a", "b", "c", "d", "e" ] a.at(0) #=> "a" a.at(-1) #=> "e"
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;
} Используя бинарный поиск, находит значение из этого массива, которое удовлетворяет заданному условию за O(log n), где n — размер массива.
Этот метод можно использовать в двух режимах: поиске минимального значения и поиске любого значения. В обоих случаях элементы массива должны быть монотонными (или отсортированными) относительно блока.
В режиме поиска минимального значения (это хороший выбор для типичных случаев использования) блок должен всегда возвращать true или false, и должен существовать индекс i (0 ≤ i ≤ ary.size), такой что:
-
блок возвращает false для любого элемента с индексом меньше i, и
-
блок возвращает true для любого элемента с индексом больше или равным i.
Этот метод возвращает i-й элемент. Если i равно ary.size, возвращает nil.
ary = [0, 4, 7, 10, 12]
ary.bsearch {|x| x >= 4 } #=> 4
ary.bsearch {|x| x >= 6 } #=> 7
ary.bsearch {|x| x >= -1 } #=> 0
ary.bsearch {|x| x >= 100 } #=> nil
В режиме поиска любого значения (это поведение аналогично libc's bsearch(3)) блок должен всегда возвращать число, и должны существовать два индекса i и j (0 ≤ i ≤ j ≤ ary.size), такие что:
-
блок возвращает положительное число для ary, если 0 ≤ k < i,
-
блок возвращает ноль для ary, если i ≤ k < j, и
-
блок возвращает отрицательное число для ary, если j ≤ k < ary.size.
В этом случае этот метод возвращает любой элемент, индекс которого находится в пределах i…j. Если i равно j (т.е., нет элемента, удовлетворяющего блоку), этот метод возвращает nil.
ary = [0, 4, 7, 10, 12]
# try to find v such that 4 <= v < 8
ary.bsearch {|x| 1 - x / 4 } #=> 4 or 7
# try to find v such that 8 <= v < 10
ary.bsearch {|x| 4 - x / 2 } #=> nil
Нельзя смешивать два режима одновременно; блок должен всегда возвращать либо true/false, либо всегда возвращать число. Не определено, какое значение фактически выбирается на каждой итерации.
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 (v == Qfalse || v == Qnil) {
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);
} Используя бинарный поиск, находит индекс значения из этого массива, которое удовлетворяет заданному условию за O(log n), где n — размер массива.
Поддерживает два режима, в зависимости от характера блока. Они точно такие же, как и в случае с методом bsearch, с единственным отличием, что этот метод возвращает индекс элемента, а не сам элемент. Для получения более подробной информации см. документацию по методу 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 = [ "a", "b", "c", "d", "e" ] 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>.
Создаёт новый массив, содержащий значения, возвращаемые блоком.
См. также Enumerable#collect.
Если блок не задан, возвращается Enumerator вместо него.
a = [ "a", "b", "c", "d" ]
a.collect {|x| x + "!"} #=> ["a!", "b!", "c!", "d!"]
a.map.with_index {|x, i| x * i} #=> ["", "b", "cc", "ddd"]
a #=> ["a", "b", "c", "d"]
static VALUE
rb_ary_collect_bang(VALUE ary)
{
long i;
RETURN_SIZED_ENUMERATOR(ary, 0, 0, ary_enum_length);
rb_ary_modify(ary);
for (i = 0; i < RARRAY_LEN(ary); i++) {
rb_ary_store(ary, i, rb_yield(RARRAY_AREF(ary, i)));
}
return ary;
} Вызывает заданный блок один раз для каждого элемента <self>, заменяя элемент возвращаемым значением блока.
См. также Enumerable#collect.
Если блок не задан, возвращается Enumerator вместо него.
a = [ "a", "b", "c", "d" ]
a.map! {|x| x + "!" }
a #=> [ "a!", "b!", "c!", "d!" ]
a.collect!.with_index {|x, i| x[0...i] }
a #=> ["", "b", "c!", "d!"]
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> элементов из массива, а затем возвращает сам массив.
Реализация не гарантирует порядок, в котором генерируются комбинации.
Если блок не задан, возвращается Enumerator вместо него.
Примеры:
a = [1, 2, 3, 4] a.combination(1).to_a #=> [[1],[2],[3],[4]] a.combination(2).to_a #=> [[1,2],[1,3],[1,4],[2,3],[2,4],[3,4]] a.combination(3).to_a #=> [[1,2,3],[1,2,4],[1,3,4],[2,3,4]] a.combination(4).to_a #=> [[1,2,3,4]] a.combination(0).to_a #=> [[]] # one combination of length 0 a.combination(5).to_a #=> [] # no combinations of length 5
static VALUE
rb_ary_compact(VALUE ary)
{
ary = rb_ary_dup(ary);
rb_ary_compact_bang(ary);
return ary;
} Возвращает копию <self> со всеми <nil> элементами удалёнными.
[ "a", nil, "b", nil, "c", nil ].compact
#=> [ "a", "b", "c" ]
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> элементы из массива.
Возвращает <nil> если не было изменений, иначе возвращает массив.
[ "a", nil, "b", nil, "c" ].compact! #=> [ "a", "b", "c" ] [ "a", "b", "c" ].compact! #=> 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_ary> в <self>.
[ "a", "b" ].concat( ["c", "d"]) #=> [ "a", "b", "c", "d" ] [ "a" ].concat( ["b"], ["c", "d"]) #=> [ "a", "b", "c", "d" ] [ "a" ].concat #=> [ "a" ] a = [ 1, 2, 3 ] a.concat( [ 4, 5 ]) a #=> [ 1, 2, 3, 4, 5 ] a = [ 1, 2 ] a.concat(a, a) #=> [1, 2, 1, 2, 1, 2]
См. также Array#+.
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);
} Возвращает количество элементов.
Если аргумент задан, подсчитывает количество элементов, равных <obj> с использованием <==>.
Если задан блок, подсчитывает количество элементов, для которых блок возвращает true.
ary = [1, 2, 4, 2]
ary.count #=> 4
ary.count(2) #=> 2
ary.count {|x| x%2 == 0} #=> 3
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;
} Вызывает заданный блок для каждого элемента <n> раз или бесконечно, если <nil> задан.
Ничего не делает, если задано не положительное число или массив пустой.
Возвращает <nil>, если цикл завершился без прерывания.
Если блок не задан, возвращается Enumerator вместо него.
a = ["a", "b", "c"]
a.cycle {|x| puts x} # print, a, b, c, a, b, c,.. forever.
a.cycle(2) {|x| puts x} # print, a, b, c, a, b, c.
# File lib/rexml/xpath_parser.rb, line 35
def dclone
klone = self.clone
klone.clear
self.each{|v| klone << v.dclone}
klone
end предоставляет унифицированную операцию clone, для REXML::XPathParser для использования в нескольких типах Object+
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>, которые равны <obj>.
Возвращает последний удалённый элемент или nil если подходящего элемента не найдено.
Если задан необязательный блок, возвращает результат блока, если элемент не найден. (Чтобы удалить <nil> элементы и получить информативное возвращаемое значение, используйте Array#compact!)
a = [ "a", "b", "b", "b", "c" ]
a.delete("b") #=> "b"
a #=> ["a", "c"]
a.delete("z") #=> nil
a.delete("z") {"not found"} #=> "not found"
static VALUE
rb_ary_delete_at_m(VALUE ary, VALUE pos)
{
return rb_ary_delete_at(ary, NUM2LONG(pos));
} Удаляет элемент по указанному <index>, возвращая этот элемент или <nil>, если <index> вне диапазона.
См. также Array#slice!
a = ["ant", "bat", "cat", "dog"] a.delete_at(2) #=> "cat" a #=> ["ant", "bat", "dog"] a.delete_at(99) #=> 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, для которого блок возвращает true.
Массив изменяется мгновенно каждый раз, когда вызывается блок, а не после завершения итерации.
См. также Array#reject!
Если блок не задан, возвращается Enumerator.
scores = [ 97, 42, 75 ]
scores.delete_if {|score| score < 80 } #=> [97]
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;
} Array Разность
Возвращает новый массив, являющийся копией исходного массива, из которого удалены все вхождения элементов, также присутствующих в other_ary. Порядок элементов сохраняется из исходного массива.
Для сравнения элементов используются методы hash и eql? для повышения эффективности.
[ 1, 1, 2, 2, 3, 3, 4, 5 ].difference([ 1, 2, 4 ]) #=> [ 3, 3, 5 ]
Обратите внимание, что, хотя 1 и 2 встречались только по одному разу в массиве-аргументе, и встречались дважды в массиве-приёмнике, все вхождения каждого Integer удаляются в возвращаемом массиве.
Можно передать несколько массивов-аргументов, и все вхождения любого элемента в переданных массивах, совпадающие с массивом-приёмником, будут удалены из возвращаемого массива.
[ 1, 'c', :s, 'yep' ].difference([ 1 ], [ 'a', 'c' ]) #=> [ :s, "yep" ]
Если вам нужна работа со множествами, см. класс библиотеки Set.
См. также 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);
} Извлекает вложенное значение, заданное последовательностью объектов idx, вызывая dig на каждом шаге, возвращая nil, если любой промежуточный шаг nil.
a = [[1, [2, 3]]]
a.dig(0, 1, 1) #=> 3
a.dig(1, 2, 3) #=> nil
a.dig(0, 0, 0) #=> TypeError: Integer does not have #dig method
[42, {foo: :bar}].dig(1, :foo) #=> :bar
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 (result == Qnil) result = rb_ary_new();
return result;
} Оставляет элементы массива ary начиная с n-го и возвращает остальные элементы в виде массива.
Если задано отрицательное число, выбрасывается исключение ArgumentError.
См. также Array#take
a = [1, 2, 3, 4, 5, 0] a.drop(3) #=> [4, 5, 0]
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));
} Оставляет элементы массива до, но не включая, первого элемента, для которого блок возвращает nil или false, и возвращает массив, содержащий оставшиеся элементы.
Если блок не задан, возвращается Enumerator.
См. также Array#take_while
a = [1, 2, 3, 4, 5, 0]
a.drop_while {|i| i < 3 } #=> [3, 4, 5, 0]
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, передавая этот элемент в качестве параметра. Возвращает сам массив.
Если блок не задан, возвращается Enumerator.
a = [ "a", "b", "c" ]
a.each {|x| print x, " -- " }
результат:
a -- b -- c --
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;
} Аналогично Array#each, но передаёт index элемента вместо самого элемента.
Если блок не задан, возвращается Enumerator.
a = [ "a", "b", "c" ]
a.each_index {|x| print x, " -- " }
результат:
0 -- 1 -- 2 --
static VALUE
rb_ary_empty_p(VALUE ary)
{
if (RARRAY_LEN(ary) == 0)
return Qtrue;
return Qfalse;
} Возвращает true, если self не содержит элементов.
[].empty? #=> true
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 являются одним и тем же объектом или являются массивами с одинаковым содержимым (согласно Object#eql?).
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, но выбрасывает исключение IndexError, если указанный index выходит за пределы массива. Это исключение можно предотвратить, передав второй аргумент, который будет действовать как значение default.
В качестве альтернативы, если задан блок, он будет выполнен только при ссылке на недействительный index.
Отрицательные значения index отсчитываются от конца массива.
a = [ 11, 22, 33, 44 ]
a.fetch(1) #=> 22
a.fetch(-1) #=> 44
a.fetch(4, 'cat') #=> "cat"
a.fetch(100) {|i| puts "#{i} is out of bounds"}
#=> "100 is out of bounds"
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 (который может быть всем массивом) в значение obj.
Значение start nil равно нулю.
Значение length nil равно длине массива.
Последние три формы заполняют массив значениями, полученными от заданного блока, которому передаётся абсолютный индекс каждого заполняемого элемента.
Отрицательные значения start отсчитываются от конца массива, где -1 — последний элемент.
a = [ "a", "b", "c", "d" ]
a.fill("x") #=> ["x", "x", "x", "x"]
a.fill("z", 2, 2) #=> ["x", "x", "z", "z"]
a.fill("y", 0..1) #=> ["y", "y", "z", "z"]
a.fill {|i| i*i} #=> [0, 1, 4, 9]
a.fill(-2) {|i| i*i*i} #=> [0, 1, 8, 27]
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;
} Возвращает новый массив, содержащий все элементы массива ary, для которых заданный block возвращает значение true.
Если блок не задан, возвращается Enumerator.
[1,2,3,4,5].select {|num| num.even? } #=> [2, 4]
a = %w[ a b c d e f ]
a.select {|v| v =~ /[aeiou]/ } #=> ["a", "e"]
См. также Enumerable#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, удаляя элементы, для которых блок возвращает значение false.
Массив может не изменяться мгновенно каждый раз при вызове блока.
Если изменения были внесены, возвращается self, в противном случае — nil.
Если блок не задан, возвращается Enumerator.
См. также Array#keep_if.
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;
} Возвращает индекс первого объекта в ary таком, что объект == к obj.
Если вместо аргумента задан блок, возвращает индекс первого объекта, для которого блок возвращает true. Возвращает nil если совпадение не найдено.
См. также Array#rindex.
Если не задан ни блок, ни аргумент, возвращается Enumerator.
a = [ "a", "b", "c" ]
a.index("b") #=> 1
a.index("z") #=> nil
a.index {|x| x == "b"} #=> 1
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);
}
} Возвращает первый элемент или первые n элементов массива. Если массив пуст, первая форма возвращает nil, а вторая форма возвращает пустой массив. См. также Array#last для обратного эффекта.
a = [ "q", "r", "s", "t" ] a.first #=> "q" a.first(2) #=> ["q", "r"]
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 определяет уровень рекурсии для развёртывания.
s = [ 1, 2, 3 ] #=> [1, 2, 3] t = [ 4, 5, 6, [7, 8] ] #=> [4, 5, 6, [7, 8]] a = [ s, t, 9, 10 ] #=> [[1, 2, 3], [4, 5, 6, [7, 8]], 9, 10] a.flatten #=> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] a = [ 1, 2, [3, [4, 5] ] ] a.flatten(1) #=> [1, 2, 3, [4, 5]]
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 на месте.
Возвращает nil если изменения не были внесены (т.е., массив не содержит подмассивов.)
Необязательный аргумент level определяет уровень рекурсии для развёртывания.
a = [ 1, 2, [3, [4, 5] ] ] a.flatten! #=> [1, 2, 3, 4, 5] a.flatten! #=> nil a #=> [1, 2, 3, 4, 5] a = [ 1, 2, [3, [4, 5] ] ] a.flatten!(1) #=> [1, 2, 3, [4, 5]]
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);
} Вычислить хэш-код для этого массива.
Два массива с одинаковым содержимым будут иметь одинаковый хэш-код (и сравниваются с использованием eql?).
См. также Object#hash.
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 если заданный object присутствует в self (то есть, если любой элемент == object), в противном случае возвращает false.
a = [ "a", "b", "c" ]
a.include?("b") #=> true
a.include?("z") #=> false
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;
} Возвращает индекс первого объекта в ary таком, что объект == к obj.
Если вместо аргумента задан блок, возвращает индекс первого объекта, для которого блок возвращает true. Возвращает nil если совпадение не найдено.
См. также Array#rindex.
Если не задан ни блок, ни аргумент, возвращается Enumerator.
a = [ "a", "b", "c" ]
a.index("b") #=> 1
a.index("z") #=> nil
a.index {|x| x == "b"} #=> 1
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_ary, усекая или расширяя при необходимости.
a = [ "a", "b", "c", "d", "e" ] a.replace([ "x", "y", "z" ]) #=> ["x", "y", "z"] a #=> ["x", "y", "z"]
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;
} Вставляет заданные значения перед элементом с заданным index.
Отрицательные индексы отсчитываются от конца массива, где -1 — последний элемент. Если используется отрицательный индекс, заданные значения будут вставлены после этого элемента, поэтому использование индекса -1 вставит значения в конец массива.
a = %w{ a b c d }
a.insert(2, 99) #=> ["a", "b", 99, "c", "d"]
a.insert(-2, 1, 2, 3) #=> ["a", "b", 99, "c", 1, 2, 3, "d"]
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);
} Создаёт строковое представление self, вызывая inspect для каждого элемента.
[ "a", "b", "c" ].to_s #=> "[\"a\", \"b\", \"c\"]"
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;
} Set Пересечение — Возвращает новый массив, содержащий уникальные элементы, общие для self и other_ary. Порядок сохраняется из исходного массива.
Для повышения эффективности сравнивает элементы с помощью методов hash и eql?.
[ 1, 1, 3, 5 ].intersection([ 3, 2, 1 ]) # => [ 1, 3 ] [ "a", "b", "z" ].intersection([ "a", "b", "c" ], [ "b" ]) # => [ "b" ] [ "a" ].intersection #=> [ "a" ]
См. также 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_warn("$, is set to non-nil value");
}
}
return rb_ary_join(ary, sep);
} Возвращает строку, созданную путём преобразования каждого элемента массива в строку, разделённых заданным separator. Если separator — nil, используется текущий $,. Если и separator, и $, — nil, используется пустая строка.
[ "a", "b", "c" ].join #=> "abc"
[ "a", "b", "c" ].join("-") #=> "a-b-c"
Для вложенных массивов join применяется рекурсивно:
[ "a", [1, 2, [:x, :y]], "b" ].join("-") #=> "a-1-2-x-y-b"
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, для которого заданный блок возвращает значение false, и возвращает self.
Если блок не задан, вместо него возвращается Enumerator.
a = %w[ a b c d e f ]
a.keep_if {|v| v =~ /[aeiou]/ } #=> ["a", "e"]
a #=> ["a", "e"]
См. также Array#select!.
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. Если массив пуст, первая форма возвращает nil.
См. также Array#first для обратного эффекта.
a = [ "w", "x", "y", "z" ] a.last #=> "z" a.last(2) #=> ["y", "z"]
static VALUE
rb_ary_length(VALUE ary)
{
long len = RARRAY_LEN(ary);
return LONG2NUM(len);
} Возвращает количество элементов в self. Может быть нулём.
[ 1, 2, 3, 4, 5 ].length #=> 5 [].length #=> 0
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.
Создаёт новый массив, содержащий значения, возвращаемые блоком.
См. также Enumerable#collect.
Если блок не задан, возвращается Enumerator вместо него.
a = [ "a", "b", "c", "d" ]
a.collect {|x| x + "!"} #=> ["a!", "b!", "c!", "d!"]
a.map.with_index {|x, i| x * i} #=> ["", "b", "cc", "ddd"]
a #=> ["a", "b", "c", "d"]
static VALUE
rb_ary_collect_bang(VALUE ary)
{
long i;
RETURN_SIZED_ENUMERATOR(ary, 0, 0, ary_enum_length);
rb_ary_modify(ary);
for (i = 0; i < RARRAY_LEN(ary); i++) {
rb_ary_store(ary, i, rb_yield(RARRAY_AREF(ary, i)));
}
return ary;
} Вызывает заданный блок один раз для каждого элемента self, заменяя элемент значением, возвращаемым блоком.
См. также Enumerable#collect.
Если блок не задан, вместо него возвращается Enumerator.
a = [ "a", "b", "c", "d" ]
a.map! {|x| x + "!" }
a #=> [ "a!", "b!", "c!", "d!" ]
a.collect!.with_index {|x, i| x[0...i] }
a #=> ["", "b", "c!", "d!"]
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);
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 {
for (i = 0; i < RARRAY_LEN(ary); i++) {
v = RARRAY_AREF(ary, i);
if (result == Qundef || OPTIMIZED_CMP(v, result, cmp_opt) > 0) {
result = v;
}
}
}
if (result == Qundef) return Qnil;
return result;
} Возвращает объект в ary с максимальным значением. Первый вариант предполагает, что все объекты реализуют Comparable; второй использует блок для возврата a <=> b.
ary = %w(albatross dog horse)
ary.max #=> "horse"
ary.max {|a, b| a.length <=> b.length} #=> "albatross"
Если указан аргумент n, возвращаются максимальные n элементы в виде массива.
ary = %w[albatross dog horse]
ary.max(2) #=> ["horse", "dog"]
ary.max(2) {|a, b| a.length <=> b.length } #=> ["albatross", "horse"]
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);
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 {
for (i = 0; i < RARRAY_LEN(ary); i++) {
v = RARRAY_AREF(ary, i);
if (result == Qundef || OPTIMIZED_CMP(v, result, cmp_opt) < 0) {
result = v;
}
}
}
if (result == Qundef) return Qnil;
return result;
} Возвращает объект в ary с минимальным значением. Первый вариант предполагает, что все объекты реализуют Comparable; второй использует блок для возврата a <=> b.
ary = %w(albatross dog horse)
ary.min #=> "albatross"
ary.min {|a, b| a.length <=> b.length} #=> "dog"
Если указан аргумент n, возвращаются минимальные n элементы в виде массива.
ary = %w[albatross dog horse]
ary.min(2) #=> ["albatross", "dog"]
ary.min(2) {|a, b| a.length <=> b.length } #=> ["dog", "horse"]
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));
} Возвращает массив из двух элементов, содержащий минимальное и максимальное значение в массиве.
Можно указать необязательный блок для переопределения метода сравнения по умолчанию a <=> b.
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;
} См. также 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;
} См. также Enumerable#one?
# File pack.rb, line 133 def pack(fmt, buffer: nil) __builtin_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”.
Обратите внимание, что опция “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 same as "n"
J> j> J!> j!> | | "L>" is 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 same as "v"
J< j< J!< j!< | | "L<" is 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;
} При вызове с блоком выводит все перестановки длиной n элементов массива, а затем возвращает сам массив.
Если n не указано, выводит все перестановки всех элементов.
Реализация не гарантирует порядок вывода перестановок.
Если блок не задан, возвращается Enumerator вместо него.
Примеры:
a = [1, 2, 3] a.permutation.to_a #=> [[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]] a.permutation(1).to_a #=> [[1],[2],[3]] a.permutation(2).to_a #=> [[1,2],[1,3],[2,1],[2,3],[3,1],[3,2]] a.permutation(3).to_a #=> [[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]] a.permutation(0).to_a #=> [[]] # one permutation of length 0 a.permutation(4).to_a #=> [] # no permutations of length 4
static VALUE
rb_ary_pop_m(int argc, VALUE *argv, VALUE ary)
{
VALUE result;
if (argc == 0) {
return rb_ary_pop(ary);
}
rb_ary_modify_check(ary);
result = ary_take_first_or_last(argc, argv, ary, ARY_TAKE_LAST);
ARY_INCREASE_LEN(ary, -RARRAY_LEN(result));
ary_verify(ary);
return result;
} Удаляет последний элемент из self и возвращает его или nil, если массив пуст.
Если задано число n, возвращает массив последних n элементов (или меньше), аналогично тому, как это делает array.slice!(-n, n). См. также Array#push для обратного эффекта.
a = [ "a", "b", "c", "d" ] a.pop #=> "d" a.pop(2) #=> ["b", "c"] a #=> ["a"]
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 и массивов аргументов.
Если задан блок, product выведет все комбинации и вернёт self вместо него.
[1,2,3].product([4,5]) #=> [[1,4],[1,5],[2,4],[2,5],[3,4],[3,5]]
[1,2].product([1,2]) #=> [[1,1],[1,2],[2,1],[2,2]]
[1,2].product([3,4],[5,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,2].product() #=> [[1],[2]]
[1,2].product([]) #=> []
static VALUE
rb_ary_push_m(int argc, VALUE *argv, VALUE ary)
{
return rb_ary_cat(ary, argv, argc);
} Добавляет — помещает заданный(ые) объект(ы) в конец этого массива. Это выражение возвращает сам массив, поэтому несколько добавлений можно объединить в цепочку. См. также Array#pop для обратного эффекта.
a = [ "a", "b", "c" ]
a.push("d", "e", "f")
#=> ["a", "b", "c", "d", "e", "f"]
[1, 2, 3].push(4).push(5)
#=> [1, 2, 3, 4, 5]
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;
} Ищет в массиве, элементы которого также являются массивами.
Сравнивает obj со вторым элементом каждого вложенного массива, используя obj.==.
Возвращает первый вложенный массив, который соответствует obj.
См. также Array#assoc.
a = [ [ 1, "one"], [2, "two"], [3, "three"], ["ii", "two"] ]
a.rassoc("two") #=> [2, "two"]
a.rassoc("four") #=> nil
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, для которых заданный блок не true. Порядок элементов, не отвергнутых, сохраняется.
См. также Array#delete_if
Если блок не задан, возвращается Enumerator вместо него.
static VALUE
rb_ary_reject_bang(VALUE ary)
{
RETURN_SIZED_ENUMERATOR(ary, 0, 0, ary_enum_length);
rb_ary_modify(ary);
return ary_reject_bang(ary);
} Удаляет каждый элемент self, для которого блок возвращает true, если изменений не было, возвращает nil.
Массив может не изменяться мгновенно при каждом вызове блока.
См. также Enumerable#reject и Array#delete_if.
Если блок не задан, возвращается Enumerator вместо него.
static VALUE
rb_ary_repeated_combination(VALUE ary, VALUE num)
{
long n, i, len;
n = NUM2LONG(num); /* Combination size from argument */
RETURN_SIZED_ENUMERATOR(ary, 1, &num, rb_ary_repeated_combination_size); /* Return enumerator if no block */
len = RARRAY_LEN(ary);
if (n < 0) {
/* yield nothing */
}
else if (n == 0) {
rb_yield(rb_ary_new2(0));
}
else if (n == 1) {
for (i = 0; i < RARRAY_LEN(ary); i++) {
rb_yield(rb_ary_new3(1, RARRAY_AREF(ary, i)));
}
}
else if (len == 0) {
/* yield nothing */
}
else {
volatile VALUE t0;
long *p = ALLOCV_N(long, t0, n);
VALUE ary0 = ary_make_shared_copy(ary); /* private defensive copy of ary */
RBASIC_CLEAR_CLASS(ary0);
rcombinate0(len, n, p, n, ary0); /* compute and yield repeated combinations */
ALLOCV_END(t0);
RBASIC_SET_CLASS_RAW(ary0, rb_cArray);
}
return ary;
} При вызове с блоком, генерирует все повторяющиеся комбинации длины n элементов из массива, а затем возвращает сам массив.
Реализация не гарантирует порядок, в котором генерируются повторяющиеся комбинации.
Если блок не задан, возвращается Enumerator вместо него.
Примеры:
a = [1, 2, 3]
a.repeated_combination(1).to_a #=> [[1], [2], [3]]
a.repeated_combination(2).to_a #=> [[1,1],[1,2],[1,3],[2,2],[2,3],[3,3]]
a.repeated_combination(3).to_a #=> [[1,1,1],[1,1,2],[1,1,3],[1,2,2],[1,2,3],
# [1,3,3],[2,2,2],[2,2,3],[2,3,3],[3,3,3]]
a.repeated_combination(4).to_a #=> [[1,1,1,1],[1,1,1,2],[1,1,1,3],[1,1,2,2],[1,1,2,3],
# [1,1,3,3],[1,2,2,2],[1,2,2,3],[1,2,3,3],[1,3,3,3],
# [2,2,2,2],[2,2,2,3],[2,2,3,3],[2,3,3,3],[3,3,3,3]]
a.repeated_combination(0).to_a #=> [[]] # one combination of length 0
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 элементов массива, а затем возвращает сам массив.
Реализация не гарантирует порядок, в котором генерируются повторяющиеся перестановки.
Если блок не задан, возвращается Enumerator вместо него.
Примеры:
a = [1, 2]
a.repeated_permutation(1).to_a #=> [[1], [2]]
a.repeated_permutation(2).to_a #=> [[1,1],[1,2],[2,1],[2,2]]
a.repeated_permutation(3).to_a #=> [[1,1,1],[1,1,2],[1,2,1],[1,2,2],
# [2,1,1],[2,1,2],[2,2,1],[2,2,2]]
a.repeated_permutation(0).to_a #=> [[]] # one permutation of length 0
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_ary, укорачивая или расширяя при необходимости.
a = [ "a", "b", "c", "d", "e" ] a.replace([ "x", "y", "z" ]) #=> ["x", "y", "z"] a #=> ["x", "y", "z"]
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", "b", "c" ].reverse #=> ["c", "b", "a"] [ 1 ].reverse #=> [1]
static VALUE
rb_ary_reverse_bang(VALUE ary)
{
return rb_ary_reverse(ary);
} Инвертирует self на месте.
a = [ "a", "b", "c" ] a.reverse! #=> ["c", "b", "a"] a #=> ["c", "b", "a"]
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;
} Аналогично Array#each, но обходит self в обратном порядке.
a = [ "a", "b", "c" ]
a.reverse_each {|x| print x, " " }
выводит:
c b a
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;
} Возвращает индекс последнего объекта в self == в obj.
Если вместо аргумента задан блок, возвращает индекс первого объекта, для которого блок возвращает true, начиная с последнего объекта.
Возвращает nil , если совпадений не найдено.
См. также Array#index.
Если ни блок, ни аргумент не заданы, возвращается Enumerator вместо него.
a = [ "a", "b", "b", "b", "c" ]
a.rindex("b") #=> 3
a.rindex("z") #=> nil
a.rindex {|x| x == "b"} #=> 3
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 так, чтобы элемент в позиции count стал первым элементом нового массива.
Если count отрицательно, происходит вращение в обратном направлении, начиная с конца self, где -1 - последний элемент.
a = [ "a", "b", "c", "d" ] a.rotate #=> ["b", "c", "d", "a"] a #=> ["a", "b", "c", "d"] a.rotate(2) #=> ["c", "d", "a", "b"] a.rotate(-3) #=> ["b", "c", "d", "a"]
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 на месте так, чтобы элемент в позиции count стал первым, и возвращает self.
Если count отрицательно, происходит вращение в обратном направлении, начиная с конца массива, где -1 - последний элемент.
a = [ "a", "b", "c", "d" ] a.rotate! #=> ["b", "c", "d", "a"] a #=> ["b", "c", "d", "a"] a.rotate!(2) #=> ["d", "a", "b", "c"] a.rotate!(-3) #=> ["a", "b", "c", "d"]
static VALUE
rb_ary_sample(int argc, VALUE *argv, VALUE ary)
{
VALUE nv, result;
VALUE opts, randgen = rb_cRandom;
long n, len, i, j, k, idx[10];
long rnds[numberof(idx)];
long memo_threshold;
if (OPTHASH_GIVEN_P(opts)) {
VALUE rnd;
ID keyword_ids[1];
keyword_ids[0] = id_random;
rb_get_kwargs(opts, keyword_ids, 0, 1, &rnd);
if (rnd != Qundef) {
randgen = rnd;
}
}
len = RARRAY_LEN(ary);
if (rb_check_arity(argc, 0, 1) == 0) {
if (len < 2)
i = 0;
else
i = RAND_UPTO(len);
return rb_ary_elt(ary, i);
}
nv = argv[0];
n = NUM2LONG(nv);
if (n < 0) rb_raise(rb_eArgError, "negative sample number");
if (n > len) n = len;
if (n <= numberof(idx)) {
for (i = 0; i < n; ++i) {
rnds[i] = RAND_UPTO(len - i);
}
}
k = len;
len = RARRAY_LEN(ary);
if (len < k && n <= numberof(idx)) {
for (i = 0; i < n; ++i) {
if (rnds[i] >= len) return rb_ary_new_capa(0);
}
}
if (n > len) n = len;
switch (n) {
case 0:
return rb_ary_new_capa(0);
case 1:
i = rnds[0];
return rb_ary_new_from_values(1, &RARRAY_AREF(ary, i));
case 2:
i = rnds[0];
j = rnds[1];
if (j >= i) j++;
return rb_ary_new_from_args(2, RARRAY_AREF(ary, i), RARRAY_AREF(ary, j));
case 3:
i = rnds[0];
j = rnds[1];
k = rnds[2];
{
long l = j, g = i;
if (j >= i) l = i, g = ++j;
if (k >= l && (++k >= g)) ++k;
}
return rb_ary_new_from_args(3, RARRAY_AREF(ary, i), RARRAY_AREF(ary, j), RARRAY_AREF(ary, k));
}
memo_threshold =
len < 2560 ? len / 128 :
len < 5120 ? len / 64 :
len < 10240 ? len / 32 :
len / 16;
if (n <= numberof(idx)) {
long sorted[numberof(idx)];
sorted[0] = idx[0] = rnds[0];
for (i=1; i<n; i++) {
k = rnds[i];
for (j = 0; j < i; ++j) {
if (k < sorted[j]) break;
++k;
}
memmove(&sorted[j+1], &sorted[j], sizeof(sorted[0])*(i-j));
sorted[j] = idx[i] = k;
}
result = rb_ary_new_capa(n);
RARRAY_PTR_USE_TRANSIENT(result, ptr_result, {
for (i=0; i<n; i++) {
ptr_result[i] = RARRAY_AREF(ary, idx[i]);
}
});
}
else if (n <= memo_threshold / 2) {
long max_idx = 0;
#undef RUBY_UNTYPED_DATA_WARNING
#define RUBY_UNTYPED_DATA_WARNING 0
VALUE vmemo = Data_Wrap_Struct(0, 0, st_free_table, 0);
st_table *memo = st_init_numtable_with_size(n);
DATA_PTR(vmemo) = memo;
result = rb_ary_new_capa(n);
RARRAY_PTR_USE(result, ptr_result, {
for (i=0; i<n; i++) {
long r = RAND_UPTO(len-i) + i;
ptr_result[i] = r;
if (r > max_idx) max_idx = r;
}
len = RARRAY_LEN(ary);
if (len <= max_idx) n = 0;
else if (n > len) n = len;
RARRAY_PTR_USE_TRANSIENT(ary, ptr_ary, {
for (i=0; i<n; i++) {
long j2 = j = ptr_result[i];
long i2 = i;
st_data_t value;
if (st_lookup(memo, (st_data_t)i, &value)) i2 = (long)value;
if (st_lookup(memo, (st_data_t)j, &value)) j2 = (long)value;
st_insert(memo, (st_data_t)j, (st_data_t)i2);
ptr_result[i] = ptr_ary[j2];
}
});
});
DATA_PTR(vmemo) = 0;
st_free_table(memo);
}
else {
result = rb_ary_dup(ary);
RBASIC_CLEAR_CLASS(result);
RB_GC_GUARD(ary);
RARRAY_PTR_USE(result, ptr_result, {
for (i=0; i<n; i++) {
j = RAND_UPTO(len-i) + i;
nv = ptr_result[j];
ptr_result[j] = ptr_result[i];
ptr_result[i] = nv;
}
});
RBASIC_SET_CLASS_RAW(result, rb_cArray);
}
ARY_SET_LEN(result, n);
return result;
} Выбирает случайный элемент или n случайных элементов из массива.
Элементы выбираются с помощью случайных и уникальных индексов в массиве, чтобы гарантировать, что элемент не повторяется, если только массив уже не содержал дубликатов.
Если массив пуст, первая форма возвращает nil, а вторая - пустой массив.
a = [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ] a.sample #=> 7 a.sample(4) #=> [6, 4, 2, 5]
Необязательный аргумент rng будет использоваться в качестве генератора случайных чисел.
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;
} Возвращает новый массив, содержащий все элементы ary, для которых заданный block возвращает значение истины.
Если блок не задан, возвращается Enumerator вместо него.
[1,2,3,4,5].select {|num| num.even? } #=> [2, 4]
a = %w[ a b c d e f ]
a.select {|v| v =~ /[aeiou]/ } #=> ["a", "e"]
См. также Enumerable#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, удаляя элементы, для которых блок возвращает false значение.
Массив может не изменяться мгновенно при каждом вызове блока.
Если изменения были произведены, возвращает self, в противном случае возвращает nil.
Если блок не задан, возвращается Enumerator вместо него.
См. также Array#keep_if.
Array#filter! - псевдоним для Array#select!.
# File lib/shellwords.rb, line 228 def shelljoin Shellwords.join(self) end
Создаёт строку командной строки из списка аргументов array, соединяя все элементы, экранированные для оболочки Bourne и разделённые пробелом.
См. Shellwords.shelljoin для получения подробностей.
static VALUE
rb_ary_shift_m(int argc, VALUE *argv, VALUE ary)
{
VALUE result;
long n;
if (argc == 0) {
return rb_ary_shift(ary);
}
rb_ary_modify_check(ary);
result = ary_take_first_or_last(argc, argv, ary, ARY_TAKE_FIRST);
n = RARRAY_LEN(result);
rb_ary_behead(ary,n);
return result;
} Удаляет первый элемент из self и возвращает его (сдвигая все остальные элементы вниз на одну позицию). Возвращает nil , если массив пуст.
Если задано число n, возвращает массив из первых n элементов (или меньше), так же как и array.slice!(0, n). При этом массив ary будет содержать только оставшиеся элементы, не включая сдвинутые в new_ary. См. также Array#unshift для противоположного эффекта.
args = [ "-m", "-q", "filename" ] args.shift #=> "-m" args #=> ["-q", "filename"] args = [ "-m", "-q", "filename" ] args.shift(2) #=> ["-m", "-q"] args #=> ["filename"]
static VALUE
rb_ary_shuffle(int argc, VALUE *argv, VALUE ary)
{
ary = rb_ary_dup(ary);
rb_ary_shuffle_bang(argc, argv, ary);
return ary;
} Возвращает новый массив с элементами self перемешанными.
a = [ 1, 2, 3 ] #=> [1, 2, 3] a.shuffle #=> [2, 3, 1] a #=> [1, 2, 3]
Необязательный аргумент rng будет использован в качестве генератора случайных чисел.
a.shuffle(random: Random.new(1)) #=> [1, 3, 2]
static VALUE
rb_ary_shuffle_bang(int argc, VALUE *argv, VALUE ary)
{
VALUE opts, randgen = rb_cRandom;
long i, len;
if (OPTHASH_GIVEN_P(opts)) {
VALUE rnd;
ID keyword_ids[1];
keyword_ids[0] = id_random;
rb_get_kwargs(opts, keyword_ids, 0, 1, &rnd);
if (rnd != Qundef) {
randgen = rnd;
}
}
rb_check_arity(argc, 0, 0);
rb_ary_modify(ary);
i = len = RARRAY_LEN(ary);
RARRAY_PTR_USE(ary, ptr, {
while (i) {
long j = RAND_UPTO(i);
VALUE tmp;
if (len != RARRAY_LEN(ary) || ptr != RARRAY_CONST_PTR_TRANSIENT(ary)) {
rb_raise(rb_eRuntimeError, "modified during shuffle");
}
tmp = ptr[--i];
ptr[i] = ptr[j];
ptr[j] = tmp;
}
}); /* WB: no new reference */
return ary;
} Перемешивает элементы в self на месте.
a = [ 1, 2, 3 ] #=> [1, 2, 3] a.shuffle! #=> [2, 3, 1] a #=> [2, 3, 1]
Необязательный аргумент rng будет использован в качестве генератора случайных чисел.
a.shuffle!(random: Random.new(1)) #=> [1, 3, 2]
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]);
} Ссылка на элемент — Возвращает элемент по index, или возвращает подмассив, начинающийся с start индекса и продолжающийся length элементов, или возвращает подмассив, заданный range индексами.
Отрицательные индексы считаются от конца массива (–1 — последний элемент). В start и range случаях начальный индекс находится перед элементом. Кроме того, при индексе диапазона элементов в конце массива возвращается пустой массив.
Возвращает nil , если индекс (или начальный индекс) выходит за пределы диапазона.
a = [ "a", "b", "c", "d", "e" ] a[2] + a[0] + a[1] #=> "cab" a[6] #=> nil a[1, 2] #=> [ "b", "c" ] a[1..3] #=> [ "b", "c", "d" ] a[4..7] #=> [ "e" ] a[6..10] #=> nil a[-3, 3] #=> [ "c", "d", "e" ] # special cases a[5] #=> nil a[6, 1] #=> nil a[5, 1] #=> [] a[5..10] #=> []
static VALUE
rb_ary_slice_bang(int argc, VALUE *argv, VALUE ary)
{
VALUE arg1, arg2;
long pos, len, orig_len;
rb_ary_modify_check(ary);
if (argc == 2) {
pos = NUM2LONG(argv[0]);
len = NUM2LONG(argv[1]);
delete_pos_len:
if (len < 0) return Qnil;
orig_len = RARRAY_LEN(ary);
if (pos < 0) {
pos += orig_len;
if (pos < 0) return Qnil;
}
else if (orig_len < pos) return Qnil;
if (orig_len < pos + len) {
len = orig_len - pos;
}
if (len == 0) return rb_ary_new2(0);
arg2 = rb_ary_new4(len, RARRAY_CONST_PTR_TRANSIENT(ary)+pos);
RBASIC_SET_CLASS(arg2, rb_obj_class(ary));
rb_ary_splice(ary, pos, len, 0, 0);
return arg2;
}
rb_check_arity(argc, 1, 2);
arg1 = argv[0];
if (!FIXNUM_P(arg1)) {
switch (rb_range_beg_len(arg1, &pos, &len, RARRAY_LEN(ary), 0)) {
case Qtrue:
/* valid range */
goto delete_pos_len;
case Qnil:
/* invalid range */
return Qnil;
default:
/* not a range */
break;
}
}
return rb_ary_delete_at(ary, NUM2LONG(arg1));
} Удаляет элемент(ы), заданные index (необязательно до length элементов) или range.
Возвращает удалённый объект (или объекты), или nil , если index выходит за пределы диапазона.
a = [ "a", "b", "c" ] a.slice!(1) #=> "b" a #=> ["a", "c"] a.slice!(-1) #=> "c" a #=> ["a"] a.slice!(100) #=> nil a #=> ["a"]
VALUE
rb_ary_sort(VALUE ary)
{
ary = rb_ary_dup(ary);
rb_ary_sort_bang(ary);
return ary;
} Возвращает новый массив, созданный путём сортировки self.
Сравнения для сортировки будут выполняться с помощью оператора <=> или с помощью необязательного блока кода.
Блок должен реализовать сравнение между a и b и возвращать целое число меньше 0, когда b следует за a, 0 когда a и b эквивалентны, или целое число больше 0, когда a следует за b.
Результат не гарантируется как стабильный. Когда сравнение двух элементов возвращает 0, порядок элементов непредсказуем.
ary = [ "d", "a", "e", "c", "b" ]
ary.sort #=> ["a", "b", "c", "d", "e"]
ary.sort {|a, b| b <=> a} #=> ["e", "d", "c", "b", "a"]
Для получения обратного порядка также можно использовать (и это может быть быстрее):
ary.sort.reverse! #=> ["e", "d", "c", "b", "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.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 на месте.
Сравнения для сортировки будут выполняться с помощью оператора <=> или с помощью необязательного блока кода.
Блок должен реализовать сравнение между a и b и возвращать целое число меньше 0, когда b следует за a, 0 когда a и b эквивалентны, или целое число больше 0, когда a следует за b.
Результат не гарантируется как стабильный. Когда сравнение двух элементов возвращает 0, порядок элементов непредсказуем.
ary = [ "d", "a", "e", "c", "b" ]
ary.sort! #=> ["a", "b", "c", "d", "e"]
ary.sort! {|a, b| b <=> a} #=> ["e", "d", "c", "b", "a"]
См. также Enumerable#sort_by.
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 через заданный блок.
Результат не гарантируется как стабильный. Если два ключа равны, порядок соответствующих элементов непредсказуем.
Если блок не задан, вместо этого возвращается Enumerator.
См. также Enumerable#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_TYPE_P(e, T_BIGNUM))
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 http://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_TYPE_P(e, T_BIGNUM))
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;
} Возвращает сумму элементов. Например, [e1, e2, e3].sum возвращает init + e1 + e2 + e3.
Если задан блок, блок применяется к каждому элементу перед сложением.
Если ary пустой, возвращает init.
[].sum #=> 0
[].sum(0.0) #=> 0.0
[1, 2, 3].sum #=> 6
[3, 5.5].sum #=> 8.5
[2.5, 3.0].sum(0.0) {|e| e * e } #=> 15.25
[Object.new].sum #=> TypeError
Среднее значение (арифметическое) массива можно получить следующим образом.
mean = ary.sum(0.0) / ary.length
Этот метод может быть использован для нечисловых объектов с явным аргументом init.
["a", "b", "c"].sum("") #=> "abc"
[[1], [[2]], [3]].sum([]) #=> [1, [2], 3]
Однако, Array#join и Array#flatten быстрее, чем Array#sum, для массива строк и массива массивов.
["a", "b", "c"].join #=> "abc" [[1], [[2]], [3]].flatten(1) #=> [1, [2], 3]
Метод 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 элементов массива.
Если задано отрицательное число, возникает исключение ArgumentError.
См. также Array#drop
a = [1, 2, 3, 4, 5, 0] a.take(3) #=> [1, 2, 3]
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 или false, затем останавливает итерацию и возвращает массив всех предыдущих элементов.
Если блок не задан, вместо этого возвращается Enumerator.
См. также Array#drop_while
a = [1, 2, 3, 4, 5, 0]
a.take_while {|i| i < 3} #=> [1, 2]
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;
} Возвращает результат интерпретации ary как массива пар [key, value].
[[:foo, :bar], [1, 2]].to_h
# => {:foo => :bar, 1 => 2}
Если задан блок, результаты применения блока к каждому элементу массива будут использованы как пары.
["foo", "bar"].to_h {|s| [s.ord, s]}
# => {102=>"foo", 98=>"bar"}
static VALUE
rb_ary_transpose(VALUE ary)
{
long elen = -1, alen, i, j;
VALUE tmp, result = 0;
alen = RARRAY_LEN(ary);
if (alen == 0) return rb_ary_dup(ary);
for (i=0; i<alen; i++) {
tmp = to_ary(rb_ary_elt(ary, i));
if (elen < 0) { /* first element */
elen = RARRAY_LEN(tmp);
result = rb_ary_new2(elen);
for (j=0; j<elen; j++) {
rb_ary_store(result, j, rb_ary_new2(alen));
}
}
else if (elen != RARRAY_LEN(tmp)) {
rb_raise(rb_eIndexError, "element size differs (%ld should be %ld)",
RARRAY_LEN(tmp), elen);
}
for (j=0; j<elen; j++) {
rb_ary_store(rb_ary_elt(result, j), i, rb_ary_elt(tmp, j));
}
}
return result;
} Предполагает, что self является массивом массивов и транспонирует строки и столбцы.
a = [[1,2], [3,4], [5,6]] a.transpose #=> [[1, 3, 5], [2, 4, 6]]
Если длина подмассивов не совпадает, генерируется IndexError.
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;
} Set Объединение — Возвращает новый массив, объединяя other_ary с self, исключая дубликаты и сохраняя порядок из исходных массивов.
Для повышения эффективности сравнивает элементы по методам hash и eql?.
[ "a", "b", "c" ].union( [ "c", "d", "a" ] ) #=> [ "a", "b", "c", "d" ] [ "a" ].union( ["e", "b"], ["a", "c", "b"] ) #=> [ "a", "e", "b", "c" ] [ "a" ].union #=> [ "a" ]
См. также 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);
}
RBASIC_SET_CLASS(uniq, rb_obj_class(ary));
if (hash) {
ary_recycle_hash(hash);
}
return uniq;
} Возвращает новый массив, удаляя дублирующие значения в self.
Если задан блок, для сравнения будет использоваться возвращаемое значение блока.
Для повышения эффективности сравнивает значения по методам hash и eql?.
self просматривается в порядке следования, и сохраняется первое вхождение.
a = [ "a", "a", "b", "b", "c" ]
a.uniq # => ["a", "b", "c"]
b = [["student","sam"], ["student","george"], ["teacher","matz"]]
b.uniq {|s| s.first} # => [["student", "sam"], ["teacher", "matz"]]
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;
} Удаляет дублирующие элементы из self.
Если задан блок, для сравнения будет использоваться возвращаемое значение блока.
Для повышения эффективности сравнивает значения по методам hash и eql?.
self просматривается в порядке следования, и сохраняется первое вхождение.
Возвращает nil если изменений не произошло (то есть дубликаты не найдены).
a = [ "a", "a", "b", "b", "c" ]
a.uniq! # => ["a", "b", "c"]
b = [ "a", "b", "c" ]
b.uniq! # => nil
c = [["student","sam"], ["student","george"], ["teacher","matz"]]
c.uniq! {|s| s.first} # => [["student", "sam"], ["teacher", "matz"]]
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;
} Добавляет объекты в начало self, перемещая другие элементы вверх. См. также Array#shift для противоположного эффекта.
a = [ "b", "c", "d" ]
a.unshift("a") #=> ["a", "b", "c", "d"]
a.unshift(1, 2) #=> [ 1, 2, "a", "b", "c", "d"]
static VALUE
rb_ary_values_at(int argc, VALUE *argv, VALUE ary)
{
long i, olen = RARRAY_LEN(ary);
VALUE result = rb_ary_new_capa(argc);
for (i = 0; i < argc; ++i) {
append_values_at_single(result, ary, olen, argv[i]);
}
RB_GC_GUARD(ary);
return result;
} Возвращает массив, содержащий элементы в self по соответствующим заданным selector.
Селекторы могут быть целыми индексами или диапазонами.
См. также Array#select.
a = %w{ a b c d e f }
a.values_at(1, 3, 5) # => ["b", "d", "f"]
a.values_at(1, 3, 5, 7) # => ["b", "d", "f", nil]
a.values_at(-1, -2, -2, -7) # => ["f", "e", "e", nil]
a.values_at(4..6, 3...6) # => ["e", "f", nil, "d", "e", "f"]
static VALUE
rb_ary_zip(int argc, VALUE *argv, VALUE ary)
{
int i, j;
long len = RARRAY_LEN(ary);
VALUE result = Qnil;
for (i=0; i<argc; i++) {
argv[i] = take_items(argv[i], len);
}
if (rb_block_given_p()) {
int arity = rb_block_arity();
if (arity > 1) {
VALUE work, *tmp;
tmp = ALLOCV_N(VALUE, work, argc+1);
for (i=0; i<RARRAY_LEN(ary); i++) {
tmp[0] = RARRAY_AREF(ary, i);
for (j=0; j<argc; j++) {
tmp[j+1] = rb_ary_elt(argv[j], i);
}
rb_yield_values2(argc+1, tmp);
}
if (work) ALLOCV_END(work);
}
else {
for (i=0; i<RARRAY_LEN(ary); i++) {
VALUE tmp = rb_ary_new2(argc+1);
rb_ary_push(tmp, RARRAY_AREF(ary, i));
for (j=0; j<argc; j++) {
rb_ary_push(tmp, rb_ary_elt(argv[j], i));
}
rb_yield(tmp);
}
}
}
else {
result = rb_ary_new_capa(len);
for (i=0; i<len; i++) {
VALUE tmp = rb_ary_new_capa(argc+1);
rb_ary_push(tmp, RARRAY_AREF(ary, i));
for (j=0; j<argc; j++) {
rb_ary_push(tmp, rb_ary_elt(argv[j], i));
}
rb_ary_push(result, tmp);
}
}
return result;
} Преобразует любые аргументы в массивы, затем объединяет элементы self с соответствующими элементами каждого аргумента.
Это генерирует последовательность ary.size n-элементных массивов, где n — на единицу больше, чем количество аргументов.
Если размер любого аргумента меньше размера начального массива, будут добавлены nil значения.
Если задан блок, он вызывается для каждого выходного array, в противном случае возвращается массив массивов.
a = [ 4, 5, 6 ] b = [ 7, 8, 9 ] [1, 2, 3].zip(a, b) #=> [[1, 4, 7], [2, 5, 8], [3, 6, 9]] [1, 2].zip(a, b) #=> [[1, 4, 7], [2, 5, 8]] a.zip([1, 2], [8]) #=> [[4, 1, 8], [5, 2, nil], [6, nil, nil]]
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;
} Set Объединение — Возвращает новый массив, объединяя ary с other_ary, исключая дубликаты и сохраняя порядок из исходных массивов.
Для повышения эффективности сравнивает элементы по методам hash и eql?.
[ "a", "b", "c" ] | [ "c", "d", "a" ] #=> [ "a", "b", "c", "d" ] [ "c", "d", "a" ] | [ "a", "b", "c" ] #=> [ "c", "d", "a", "b" ]
См. также Array#union.
Ruby Core © 1993–2017 Yukihiro Matsumoto
Licensed under the Ruby License.
Ruby Standard Library © contributors
Licensed under their own licenses.