Spec-Zone.ru › Ruby 2.3

класс Array

Родитель:
Объект
Включенные модули:
Enumerable

Массивы — это упорядоченные коллекции объектов с целочисленными индексами.

Индексация массива начинается с 0, как в C или Java. Отрицательный индекс предполагается относительным к концу массива — то есть индекс -1 указывает на последний элемент массива, -2 — на предпоследний и так далее.

Создание массивов

Новый массив можно создать, используя литеральный конструктор []. Массивы могут содержать различные типы объектов. Например, массив ниже содержит целое число, строку и число с плавающей точкой:

ary = [1, "two", 3.0] #=> [1, "two", 3.0]

Массив также можно создать, явно вызвав ::new с нулём, одним (начальный размер массива) или двумя аргументами (начальный размер и значение по умолчанию).

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 имеет собственные методы для доступа, поиска и других манипуляций с массивами.

Некоторые из наиболее распространённых из них проиллюстрированы ниже.

Доступ к элементам

Элементы массива можно получить, используя метод #[]. Он может принимать один целочисленный аргумент (числовой индекс), пару аргументов (начало и длина) или диапазон. Отрицательные индексы начинают отсчёт с конца, где -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 работает аналогично #[].

Чтобы вызвать ошибку для индексов за пределами границ массива или предоставить значение по умолчанию, когда это произойдёт, вы можете использовать fetch.

arr = ['a', 'b', 'c', 'd', 'e', 'f']
arr.fetch(100) #=> IndexError: index 100 outside of array bounds: -6...6
arr.fetch(100, "oops") #=> "oops"

Специальные методы first и last возвращают первый и последний элементы массива соответственно.

arr.first #=> 1
arr.last  #=> 6

Чтобы вернуть первые n элементов массива, используйте take

arr.take(3) #=> [1, 2, 3]

drop делает обратное take, возвращая элементы после того, как n элементов были удалены:

arr.drop(3) #=> [4, 5, 6]

Получение информации о массиве

Массивы отслеживают свою длину постоянно. Чтобы узнать количество элементов в массиве, используйте length, count или size.

browsers = ['Chrome', 'Firefox', 'Safari', 'Opera', 'IE']
browsers.length #=> 5
browsers.count #=> 5

Чтобы проверить, содержит ли массив какие-либо элементы вообще

browsers.empty? #=> false

Чтобы проверить, включён ли определённый элемент в массив

browsers.include?('Konqueror') #=> false

Добавление элементов в массивы

Элементы можно добавлять в конец массива, используя либо push, либо <<

arr = [1, 2, 3, 4]
arr.push(5) #=> [1, 2, 3, 4, 5]
arr << 6    #=> [1, 2, 3, 4, 5, 6]

unshift добавит новый элемент в начало массива.

arr.unshift(0) #=> [0, 1, 2, 3, 4, 5, 6]

С помощью insert вы можете добавить новый элемент в массив в любой позиции.

arr.insert(3, 'apple')  #=> [0, 1, 2, 'apple', 3, 4, 5, 6]

Используя метод insert, вы также можете вставить сразу несколько значений:

arr.insert(3, 'orange', 'pear', 'grapefruit')
#=> [0, 1, 2, "orange", "pear", "grapefruit", "apple", 3, 4, 5, 6]

Удаление элементов из массива

Метод pop удаляет последний элемент в массиве и возвращает его:

arr =  [1, 2, 3, 4, 5, 6]
arr.pop #=> 6
arr #=> [1, 2, 3, 4, 5]

Чтобы получить и одновременно удалить первый элемент, используйте shift:

arr.shift #=> 1
arr #=> [2, 3, 4, 5]

Чтобы удалить элемент по определённому индексу:

arr.delete_at(2) #=> 4
arr #=> [2, 3, 5]

Чтобы удалить определённый элемент где-либо в массиве, используйте delete:

arr = [1, 2, 2, 3]
arr.delete(2) #=> 2
arr #=> [1,3]

Полезный метод, если вам нужно удалить nil значения из массива, — compact:

arr = ['foo', 0, nil, 'bar', 7, 'baz', nil]
arr.compact  #=> ['foo', 0, 'bar', 7, 'baz']
arr          #=> ['foo', 0, nil, 'bar', 7, 'baz', nil]
arr.compact! #=> ['foo', 0, 'bar', 7, 'baz']
arr          #=> ['foo', 0, 'bar', 7, 'baz']

Другая распространённая необходимость — удаление дублирующих элементов из массива.

Он имеет неразрушающий метод uniq и разрушающий метод uniq!

arr = [2, 5, 6, 556, 6, 6, 8, 9, 0, 123, 556]
arr.uniq #=> [2, 5, 6, 556, 8, 9, 0, 123]

Итерация по массивам

Как и все классы, включающие модуль Enumerable, массив имеет метод each, который определяет, какие элементы должны быть проитерированы и как. В случае each массива все элементы экземпляра массива передаются в предоставленный блок последовательно.

Обратите внимание, что эта операция не изменяет массив.

arr = [1, 2, 3, 4, 5]
arr.each { |a| print a -= 10, " " }
# prints: -9 -8 -7 -6 -5
#=> [1, 2, 3, 4, 5]

Ещё один иногда полезный итератор — reverse_each, который итерирует элементы массива в обратном порядке.

words = %w[first second third fourth fifth sixth]
str = ""
words.reverse_each { |word| str += "#{word} " }
p str #=> "sixth fifth fourth third second first "

Метод map может использоваться для создания нового массива на основе исходного массива, но со значениями, изменёнными предоставленным блоком:

arr.map { |a| 2*a }   #=> [2, 4, 6, 8, 10]
arr                   #=> [1, 2, 3, 4, 5]
arr.map! { |a| a**2 } #=> [1, 4, 9, 16, 25]
arr                   #=> [1, 4, 9, 16, 25]

Выбор элементов из массива

Элементы массива можно выбирать в соответствии с критериями, определёнными в блоке. Выбор может происходить разрушающим или неразрушающим способом. В то время как разрушающие операции изменят массив, над которым они вызваны, неразрушающие методы обычно возвращают новый массив с выбранными элементами, но оставляют исходный массив неизменным.

Неразрушающий выбор

arr = [1, 2, 3, 4, 5, 6]
arr.select { |a| a > 3 }     #=> [4, 5, 6]
arr.reject { |a| a < 3 }     #=> [3, 4, 5, 6]
arr.drop_while { |a| a < 4 } #=> [4, 5, 6]
arr                          #=> [1, 2, 3, 4, 5, 6]

Разрушающий выбор

select! и reject! — соответствующие разрушающие методы для select и reject

Аналогично select против reject, delete_if и keep_if дают совершенно противоположный результат при использовании одного и того же блока:

arr.delete_if { |a| a < 4 } #=> [4, 5, 6]
arr                         #=> [4, 5, 6]

arr = [1, 2, 3, 4, 5, 6]
arr.keep_if { |a| a < 4 } #=> [1, 2, 3]
arr                       #=> [1, 2, 3]

Общедоступные методы класса

[](*args) Показать исходный код
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/]
new(size=0, default=nil) Показать исходный код
new(array)
new(size) {|index| block }
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) && RARRAY_CONST_PTR(ary) != 0) {
            ruby_sized_xfree((void *)RARRAY_CONST_PTR(ary), ARY_HEAP_SIZE(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"}]

Поскольку все элементы массива хранят один и тот же хэш, изменения в одном из них будут влиять на все.

Если вам нужны отдельные копии, используйте версию с блоком, которая каждый раз использует результат этого блока для инициализации элемента массива:

a = Array.new(2) { Hash.new }
a[0]['cat'] = 'feline'
a # => [{"cat"=>"feline"}, {}]
try_convert(obj) → array or nil Показать исходный код
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

Публичные методы экземпляров

ary & other_ary → new_ary Показать исходный код
static VALUE
rb_ary_and(VALUE ary1, VALUE ary2)
{
    VALUE hash, ary3, v;
    st_table *table;
    st_data_t vv;
    long i;

    ary2 = to_ary(ary2);
    ary3 = rb_ary_new();
    if (RARRAY_LEN(ary2) == 0) return ary3;
    hash = ary_make_hash(ary2);
    table = rb_hash_tbl_raw(hash);

    for (i=0; i<RARRAY_LEN(ary1); i++) {
        v = RARRAY_AREF(ary1, i);
        vv = (st_data_t)v;
        if (st_delete(table, &vv, 0)) {
            rb_ary_push(ary3, v);
        }
    }
    ary_recycle_hash(hash);

    return ary3;
}

Пересечение множеств — Возвращает новый массив, содержащий элементы, общие для двух массивов, исключая дубликаты. Порядок элементов сохраняется из исходного массива.

Для повышения эффективности сравнение элементов выполняется с помощью методов hash и eql?.

[ 1, 1, 3, 5 ] & [ 1, 2, 3 ]                 #=> [ 1, 3 ]
[ 'a', 'b', 'b', 'z' ] & [ 'a', 'b', 'c' ]   #=> [ 'a', 'b' ]

См. также #uniq.

ary * int → new_ary Показать исходный код
ary * str → new_string
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(ary);
    t = RARRAY_LEN(ary);
    if (0 < t) {
        ary_memcpy(ary2, 0, t, ptr);
        while (t <= len/2) {
            ary_memcpy(ary2, t, t, RARRAY_CONST_PTR(ary2));
            t *= 2;
        }
        if (t < len) {
            ary_memcpy(ary2, t, len-t, RARRAY_CONST_PTR(ary2));
        }
    }
  out:
    OBJ_INFECT(ary2, ary);

    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"
ary + other_ary → new_ary Показать исходный код
VALUE
rb_ary_plus(VALUE x, VALUE y)
{
    VALUE z;
    long len, xlen, ylen;

    y = to_ary(y);
    xlen = RARRAY_LEN(x);
    ylen = RARRAY_LEN(y);
    len = xlen + ylen;
    z = rb_ary_new2(len);

    ary_memcpy(z, 0, xlen, RARRAY_CONST_PTR(x));
    ary_memcpy(z, xlen, ylen, RARRAY_CONST_PTR(y));
    ARY_SET_LEN(z, len);
    return z;
}

Конкатенация — Возвращает новый массив, созданный путём конкатенации двух массивов в третий.

[ 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

Это означает, что создаётся новый массив. Вследствие этого многократное использование += с массивами может быть неэффективным.

См. также #concat.

ary - other_ary → new_ary Показать исходный код
static VALUE
rb_ary_diff(VALUE ary1, VALUE ary2)
{
    VALUE ary3;
    VALUE hash;
    long i;

    hash = ary_make_hash(to_ary(ary2));
    ary3 = rb_ary_new();

    for (i=0; i<RARRAY_LEN(ary1); i++) {
        if (st_lookup(rb_hash_tbl_raw(hash), RARRAY_AREF(ary1, i), 0)) continue;
        rb_ary_push(ary3, rb_ary_elt(ary1, i));
    }
    ary_recycle_hash(hash);
    return ary3;
}

Разность массивов

Возвращает новый массив, являющийся копией исходного массива, из которого удалены все элементы, присутствующие также в other_ary. Порядок элементов сохраняется из исходного массива.

Для повышения эффективности сравнение элементов выполняется с помощью методов hash и eql?.

[ 1, 1, 2, 2, 3, 3, 4, 5 ] - [ 1, 2, 4 ]  #=>  [ 3, 3, 5 ]

Если вам нужна работа со множествами, используйте класс библиотеки Set.

ary << obj → ary Показать исходный код
VALUE
rb_ary_push(VALUE ary, VALUE item)
{
    long idx = RARRAY_LEN(ary);
    VALUE target_ary = ary_ensure_room_for_push(ary, 1);
    RARRAY_PTR_USE(ary, ptr, {
        RB_OBJ_WRITE(target_ary, &ptr[idx], item);
    });
    ARY_SET_LEN(ary, idx + 1);
    return ary;
}

Добавление — Добавляет указанный объект в конец этого массива. Это выражение возвращает сам массив, поэтому несколько добавлений могут быть объединены.

[ 1, 2 ] << "c" << "d" << [ 3, 4 ]
        #=>  [ 1, 2, "c", "d", [ 3, 4 ] ]
ary <=> other_ary → -1, 0, +1 или nil Показать исходный код
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
ary == other_ary → bool Показать исходный код
static VALUE
rb_ary_equal(VALUE ary1, VALUE ary2)
{
    if (ary1 == ary2) return Qtrue;
    if (!RB_TYPE_P(ary2, T_ARRAY)) {
        if (!rb_respond_to(ary2, idTo_ary)) {
            return Qfalse;
        }
        return rb_equal(ary2, ary1);
    }
    if (RARRAY_LEN(ary1) != RARRAY_LEN(ary2)) return Qfalse;
    if (RARRAY_CONST_PTR(ary1) == RARRAY_CONST_PTR(ary2)) return Qtrue;
    return rb_exec_recursive_paired(recursive_equal, ary1, ary2, ary2);
}

Равенство — Два массива равны, если они содержат одинаковое количество элементов и каждый элемент равен (согласно Object#==) соответствующему элементу в other_ary.

[ "a", "c" ]    == [ "a", "c", 7 ]     #=> false
[ "a", "c", 7 ] == [ "a", "c", 7 ]     #=> true
[ "a", "c", 7 ] == [ "a", "d", "f" ]   #=> false
ary[index] → obj or nil Показать исходный код
ary[start, length] → new_ary or nil
ary[range] → new_ary or nil
slice(index) → obj or nil
slice(start, length) → new_ary or nil
slice(range) → new_ary or nil
VALUE
rb_ary_aref(int argc, const VALUE *argv, VALUE ary)
{
    VALUE arg;
    long beg, len;

    if (argc == 2) {
        beg = NUM2LONG(argv[0]);
        len = NUM2LONG(argv[1]);
        if (beg < 0) {
            beg += RARRAY_LEN(ary);
        }
        return rb_ary_subseq(ary, beg, len);
    }
    if (argc != 1) {
        rb_scan_args(argc, argv, "11", NULL, NULL);
    }
    arg = argv[0];
    /* special case - speeding up */
    if (FIXNUM_P(arg)) {
        return rb_ary_entry(ary, FIX2LONG(arg));
    }
    /* check if idx is Range */
    switch (rb_range_beg_len(arg, &beg, &len, RARRAY_LEN(ary), 0)) {
      case Qfalse:
        break;
      case Qnil:
        return Qnil;
      default:
        return rb_ary_subseq(ary, beg, len);
    }
    return rb_ary_entry(ary, NUM2LONG(arg));
}

Ссылка на элемент — Возвращает элемент по 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]               #=> []
ary[index] = obj → obj Показать исходный код
ary[start, length] = obj or other_ary or nil → obj or other_ary or nil
ary[range] = obj or other_ary or nil → obj or other_ary or nil
static VALUE
rb_ary_aset(int argc, VALUE *argv, VALUE ary)
{
    long offset, beg, len;

    if (argc == 3) {
        rb_ary_modify_check(ary);
        beg = NUM2LONG(argv[0]);
        len = NUM2LONG(argv[1]);
        rb_ary_splice(ary, beg, len, argv[2]);
        return argv[2];
    }
    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 */
        rb_ary_splice(ary, beg, len, argv[1]);
        return argv[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 возникает, если отрицательный индекс указывает на позицию перед началом массива.

См. также #push и #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"]
abbrev(pattern = nil) Показать исходный код
# 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

any? [{ |obj| block }] → true or false Показать исходный код
static VALUE
rb_ary_any_p(VALUE ary)
{
    long i, len = RARRAY_LEN(ary);
    const VALUE *ptr = RARRAY_CONST_PTR(ary);

    if (!len) return Qfalse;
    if (!rb_block_given_p()) {
        for (i = 0; i < len; ++i) if (RTEST(ptr[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?

assoc(obj) → element_ary or nil Показать исходный код
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 если совпадения не найдено.

См. также #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
at(index) → obj or nil Показать исходный код
VALUE
rb_ary_at(VALUE ary, VALUE pos)
{
    return rb_ary_entry(ary, NUM2LONG(pos));
}

Возвращает элемент по index. Отрицательный индекс считает с конца self. Возвращает nil если индекс выходит за пределы диапазона. См. также #[].

a = [ "a", "b", "c", "d", "e" ]
a.at(0)     #=> "a"
a.at(-1)    #=> "e"
bsearch {|x| block } → elem Показать исходный код
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

В режиме поиска любого (это работает как bsearch(3) из libc) блок должен возвращать число, и должны существовать два индекса 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, либо всегда возвращать число. Не определено, какое значение фактически выбирается на каждой итерации.

bsearch_index {|x| block } → int or nil Показать исходный код
static VALUE
rb_ary_bsearch_index(VALUE ary)
{
    long low = 0, high = RARRAY_LEN(ary), mid;
    int smaller = 0, satisfied = 0;
    VALUE v, val;

    RETURN_ENUMERATOR(ary, 0, 0);
    while (low < high) {
        mid = low + ((high - low) / 2);
        val = rb_ary_entry(ary, mid);
        v = rb_yield(val);
        if (FIXNUM_P(v)) {
            if (v == INT2FIX(0)) return INT2FIX(mid);
            smaller = (SIGNED_VALUE)v < 0; /* Fixnum preserves its sign-bit */
        }
        else if (v == Qtrue) {
            satisfied = 1;
            smaller = 1;
        }
        else if (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.

clear → ary Показать исходный код
VALUE
rb_ary_clear(VALUE ary)
{
    rb_ary_modify_check(ary);
    ARY_SET_LEN(ary, 0);
    if (ARY_SHARED_P(ary)) {
        if (!ARY_EMBED_P(ary)) {
            rb_ary_unshare(ary);
            FL_SET_EMBED(ary);
        }
    }
    else if (ARY_DEFAULT_SIZE * 2 < ARY_CAPA(ary)) {
        ary_resize_capa(ary, ARY_DEFAULT_SIZE * 2);
    }
    return ary;
}

Удаляет все элементы из self.

a = [ "a", "b", "c", "d", "e" ]
a.clear    #=> [ ]
collect { |item| block } → new_ary Показать исходный код
collect → Enumerator
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"]
collect! {|item| block } → ary Показать исходный код
collect! → Enumerator
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!"]
combination(n) { |c| block } → ary Показать исходный код
combination(n) → Enumerator
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
compact → new_ary Показать исходный код
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" ]
compact! → ary or nil Показать исходный код
static VALUE
rb_ary_compact_bang(VALUE ary)
{
    VALUE *p, *t, *end;
    long n;

    rb_ary_modify(ary);
    p = t = (VALUE *)RARRAY_CONST_PTR(ary); /* WB: no new reference */
    end = p + RARRAY_LEN(ary);

    while (t < end) {
        if (NIL_P(*t)) t++;
        else *p++ = *t++;
    }
    n = p - RARRAY_CONST_PTR(ary);
    if (RARRAY_LEN(ary) == n) {
        return Qnil;
    }
    ary_resize_smaller(ary, n);

    return ary;
}

Удаляет элементы nil из массива.

Возвращает nil, если изменения не были внесены, в противном случае возвращает массив.

[ "a", nil, "b", nil, "c" ].compact! #=> [ "a", "b", "c" ]
[ "a", "b", "c" ].compact!           #=> nil
concat(other_ary) → ary Показать исходный код
VALUE
rb_ary_concat(VALUE x, VALUE y)
{
    rb_ary_modify_check(x);
    y = to_ary(y);
    if (RARRAY_LEN(y) > 0) {
        rb_ary_splice(x, RARRAY_LEN(x), 0, y);
    }
    return x;
}

Добавляет элементы other_ary к self.

[ "a", "b" ].concat( ["c", "d"] ) #=> [ "a", "b", "c", "d" ]
a = [ 1, 2, 3 ]
a.concat( [ 4, 5 ] )
a                                 #=> [ 1, 2, 3, 4, 5 ]

См. также Array#+.

count → int Показать исходный код
count(obj) → int
count { |item| block } → int
static VALUE
rb_ary_count(int argc, VALUE *argv, VALUE ary)
{
    long i, n = 0;

    if (argc == 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;

        rb_scan_args(argc, argv, "1", &obj);
        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, используя ==.

Если указан блок, подсчитывает количество элементов, для которых блок возвращает истинное значение.

ary = [1, 2, 4, 2]
ary.count                  #=> 4
ary.count(2)               #=> 2
ary.count { |x| x%2 == 0 } #=> 3
cycle(n=nil) { |obj| block } → nil Показать исходный код
cycle(n=nil) → Enumerator
static VALUE
rb_ary_cycle(int argc, VALUE *argv, VALUE ary)
{
    long n, i;
    VALUE nv = Qnil;

    rb_scan_args(argc, argv, "01", &nv);

    RETURN_SIZED_ENUMERATOR(ary, argc, argv, rb_ary_cycle_size);
    if (NIL_P(nv)) {
        n = -1;
    }
    else {
        n = NUM2LONG(nv);
        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.
dclone() Показать исходный код
# File lib/rexml/xpath_parser.rb, line 33
def dclone
  klone = self.clone
  klone.clear
  self.each{|v| klone << v.dclone}
  klone
end

предоставляет унифицированную операцию clone для использования REXML::XPathParser в нескольких типах Object+.

delete(obj) → item or nil Показать исходный код
delete(obj) { block } → item or result of block
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);

    return v;
}

Удаляет все элементы из self, которые равны obj.

Возвращает последний удаленный элемент или nil, если совпадений не найдено.

Если указан необязательный блок кода, возвращается результат блока, если элемент не найден. (Чтобы удалить элементы nil и получить информативное возвращаемое значение, используйте #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"
delete_at(index) → obj or nil Показать исходный код
static VALUE
rb_ary_delete_at_m(VALUE ary, VALUE pos)
{
    return rb_ary_delete_at(ary, NUM2LONG(pos));
}

Удаляет элемент по указанному index, возвращая этот элемент или nil, если index находится вне диапазона.

См. также #slice!

a = ["ant", "bat", "cat", "dog"]
a.delete_at(2)    #=> "cat"
a                 #=> ["ant", "bat", "dog"]
a.delete_at(99)   #=> nil
delete_if { |item| block } → ary Показать исходный код
delete_if → Enumerator
static VALUE
rb_ary_delete_if(VALUE ary)
{
    RETURN_SIZED_ENUMERATOR(ary, 0, 0, ary_enum_length);
    ary_reject_bang(ary);
    return ary;
}

Удаляет каждый элемент self, для которого блок вычисляется в true.

Массив изменяется немедленно каждый раз, когда вызывается блок, а не после завершения итерации.

См. также #reject!

Если блок не указан, вместо этого возвращается Enumerator.

scores = [ 97, 42, 75 ]
scores.delete_if {|score| score < 80 }   #=> [97]
dig(idx, ...) → object Показать исходный код
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)                    #=> NoMethodError, undefined method `dig' for 1:Fixnum
[42, {foo: :bar}].dig(1, :foo)    #=> :bar
drop(n) → new_ary Показать исходный код
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;
}

Удаляет первые n элементы из ary и возвращает оставшиеся элементы в массиве.

Если задано отрицательное число, генерирует исключение ArgumentError.

См. также #take

a = [1, 2, 3, 4, 5, 0]
a.drop(3)             #=> [4, 5, 0]
drop_while { |obj| block } → new_ary Показать исходный код
drop_while → Enumerator
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.

См. также #take_while

a = [1, 2, 3, 4, 5, 0]
a.drop_while {|i| i < 3 }   #=> [3, 4, 5, 0]
each { |item| block } → ary Показать исходный код
each → Enumerator
VALUE
rb_ary_each(VALUE ary)
{
    long i;

    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 --
each_index { |index| block } → ary Показать исходный код
each_index → Enumerator
static VALUE
rb_ary_each_index(VALUE ary)
{
    long i;
    RETURN_SIZED_ENUMERATOR(ary, 0, 0, ary_enum_length);

    for (i=0; i<RARRAY_LEN(ary); i++) {
        rb_yield(LONG2NUM(i));
    }
    return ary;
}

Аналогично #each, но передает index элемента вместо самого элемента.

Если блок не задан, возвращается Enumerator.

a = [ "a", "b", "c" ]
a.each_index {|x| print x, " -- " }

дает:

0 -- 1 -- 2 --
empty? → true or false Показать исходный код
static VALUE
rb_ary_empty_p(VALUE ary)
{
    if (RARRAY_LEN(ary) == 0)
        return Qtrue;
    return Qfalse;
}

Возвращает true, если self не содержит элементов.

[].empty?   #=> true
eql?(other) → true or false Показать исходный код
static VALUE
rb_ary_eql(VALUE ary1, VALUE ary2)
{
    if (ary1 == ary2) return Qtrue;
    if (!RB_TYPE_P(ary2, T_ARRAY)) return Qfalse;
    if (RARRAY_LEN(ary1) != RARRAY_LEN(ary2)) return Qfalse;
    if (RARRAY_CONST_PTR(ary1) == RARRAY_CONST_PTR(ary2)) return Qtrue;
    return rb_exec_recursive_paired(recursive_eql, ary1, ary2, ary2);
}

Возвращает true, если self и other — один и тот же объект или оба являются массивами с одинаковым содержимым (согласно Object#eql?).

fetch(index) → obj Показать исходный код
fetch(index, default) → obj
fetch(index) { |index| block } → obj
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"
fill(obj) → ary Показать исходный код
fill(obj, start [, length]) → ary
fill(obj, range ) → ary
fill { |index| block } → ary
fill(start [, length] ) { |index| block } → ary
fill(range) { |index| block } → ary
static VALUE
rb_ary_fill(int argc, VALUE *argv, VALUE ary)
{
    VALUE item, arg1, arg2;
    long beg = 0, end = 0, len = 0;
    int block_p = FALSE;

    if (rb_block_given_p()) {
        block_p = TRUE;
        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 (block_p) {
        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]
find_index(obj) → int or nil Показать исходный код
find_index { |item| block } → int or nil
find_index → Enumerator
static VALUE
rb_ary_index(int argc, VALUE *argv, VALUE ary)
{
    const VALUE *ptr;
    VALUE val;
    long i, len;

    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");
    len = RARRAY_LEN(ary);
    ptr = RARRAY_CONST_PTR(ary);
    for (i=0; i<len; i++) {
        VALUE e = ptr[i];
        switch (rb_equal_opt(e, val)) {
          case Qundef:
            if (!rb_equal(e, val)) break;
          case Qtrue:
            return LONG2NUM(i);
          case Qfalse:
            continue;
        }
        len = RARRAY_LEN(ary);
        ptr = RARRAY_CONST_PTR(ary);
    }
    return Qnil;
}

Возвращает индекс первого объекта в ary таком, что объект равен == к obj.

Если вместо аргумента задан блок, возвращает индекс первого объекта, для которого блок возвращает true. Возвращает nil , если совпадение не найдено.

См. также #rindex.

Если не задан ни блок, ни аргумент, возвращается Enumerator.

a = [ "a", "b", "c" ]
a.index("b")              #=> 1
a.index("z")              #=> nil
a.index { |x| x == "b" }  #=> 1
first → obj or nil Показать исходный код
first(n) → new_ary
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, а вторая — пустой массив. См. также #last для противоположного эффекта.

a = [ "q", "r", "s", "t" ]
a.first     #=> "q"
a.first(2)  #=> ["q", "r"]
flatten → new_ary Показать исходный код
flatten(level) → new_ary
static VALUE
rb_ary_flatten(int argc, VALUE *argv, VALUE ary)
{
    int mod = 0, level = -1;
    VALUE result, lv;

    rb_scan_args(argc, argv, "01", &lv);
    if (!NIL_P(lv)) level = NUM2INT(lv);
    if (level == 0) return ary_make_shared_copy(ary);

    result = flatten(ary, level, &mod);
    OBJ_INFECT(result, 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]]
flatten! → ary or nil Показать исходный код
flatten!(level) → ary or nil
static VALUE
rb_ary_flatten_bang(int argc, VALUE *argv, VALUE ary)
{
    int mod = 0, level = -1;
    VALUE result, lv;

    rb_scan_args(argc, argv, "01", &lv);
    rb_ary_modify_check(ary);
    if (!NIL_P(lv)) level = NUM2INT(lv);
    if (level == 0) return Qnil;

    result = flatten(ary, level, &mod);
    if (mod == 0) {
        ary_discard(result);
        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]]
frozen? → true or false Показать исходный код
static VALUE
rb_ary_frozen_p(VALUE ary)
{
    if (OBJ_FROZEN(ary)) return Qtrue;
    return Qfalse;
}

Возвращает true, если этот массив заморожен (или временно заморожен во время сортировки). См. также Object#frozen?

hash → fixnum Показать исходный код
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 LONG2FIX(h);
}

Вычисление хэш-кода для этого массива.

Два массива с одинаковым содержимым будут иметь одинаковый хэш-код (и сравнятся с помощью eql?).

См. также Object#hash.

END_OF_DOCUMENT_MARKER
include?(object) → true or false Показать исходный код
VALUE
rb_ary_includes(VALUE ary, VALUE item)
{
    long i;
    VALUE e;

    for (i=0; i<RARRAY_LEN(ary); i++) {
        e = RARRAY_AREF(ary, i);
        switch (rb_equal_opt(e, item)) {
          case Qundef:
            if (rb_equal(e, item)) return Qtrue;
            break;
          case Qtrue:
            return Qtrue;
        }
    }
    return Qfalse;
}

Возвращает значение true, если заданный object присутствует в self (то есть, если любой элемент == object), в противном случае возвращает false.

a = [ "a", "b", "c" ]
a.include?("b")   #=> true
a.include?("z")   #=> false
index(obj) → int or nil Показать исходный код
index { |item| block } → int or nil
index → Enumerator
static VALUE
rb_ary_index(int argc, VALUE *argv, VALUE ary)
{
    const VALUE *ptr;
    VALUE val;
    long i, len;

    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");
    len = RARRAY_LEN(ary);
    ptr = RARRAY_CONST_PTR(ary);
    for (i=0; i<len; i++) {
        VALUE e = ptr[i];
        switch (rb_equal_opt(e, val)) {
          case Qundef:
            if (!rb_equal(e, val)) break;
          case Qtrue:
            return LONG2NUM(i);
          case Qfalse:
            continue;
        }
        len = RARRAY_LEN(ary);
        ptr = RARRAY_CONST_PTR(ary);
    }
    return Qnil;
}

Возвращает индекс первого объекта в ary таком, что объект == к obj.

Если вместо аргумента задан блок, возвращает индекс первого объекта, для которого блок возвращает true. Возвращает nil если совпадение не найдено.

См. также #rindex.

Если ни блок, ни аргумент не заданы, возвращается Enumerator.

a = [ "a", "b", "c" ]
a.index("b")              #=> 1
a.index("z")              #=> nil
a.index { |x| x == "b" }  #=> 1
initialize_copy(other_ary) → ary Показать исходный код
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 = 0;

        if (ARY_OWNS_HEAP_P(copy)) {
            RARRAY_PTR_USE(copy, ptr, ruby_sized_xfree(ptr, ARY_HEAP_SIZE(copy)));
        }
        else if (ARY_SHARED_P(copy)) {
            shared = ARY_SHARED(copy);
            FL_UNSET_SHARED(copy);
        }
        FL_SET_EMBED(copy);
        ary_memcpy(copy, 0, RARRAY_LEN(orig), RARRAY_CONST_PTR(orig));
        if (shared) {
            rb_ary_decrement_share(shared);
        }
        ARY_SET_LEN(copy, RARRAY_LEN(orig));
    }
    else {
        VALUE shared = ary_make_shared(orig);
        if (ARY_OWNS_HEAP_P(copy)) {
            RARRAY_PTR_USE(copy, ptr, ruby_sized_xfree(ptr, ARY_HEAP_SIZE(copy)));
        }
        else {
            rb_ary_unshare_safe(copy);
        }
        FL_UNSET_EMBED(copy);
        ARY_SET_PTR(copy, RARRAY_CONST_PTR(orig));
        ARY_SET_LEN(copy, RARRAY_LEN(orig));
        rb_ary_set_shared(copy, shared);
    }
    return copy;
}

Заменяет содержимое self содержимым other_ary, усекая или расширяя при необходимости.

a = [ "a", "b", "c", "d", "e" ]
a.replace([ "x", "y", "z" ])   #=> ["x", "y", "z"]
a                              #=> ["x", "y", "z"]
insert(index, obj...) → ary Показать исходный код
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);
    }
    if (pos < 0) {
        pos++;
    }
    rb_ary_splice(ary, pos, 0, rb_ary_new4(argc - 1, argv + 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"]
inspect → string Показать исходный код
to_s → string
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.

[ "a", "b", "c" ].to_s     #=> "[\"a\", \"b\", \"c\"]"
Также псевдоним: to_s
join(separator=$,) → str Показать исходный код
static VALUE
rb_ary_join_m(int argc, VALUE *argv, VALUE ary)
{
    VALUE sep;

    rb_scan_args(argc, argv, "01", &sep);
    if (NIL_P(sep)) sep = rb_output_fs;

    return rb_ary_join(ary, sep);
}

Возвращает строку, созданную путём преобразования каждого элемента массива в строку, разделённых заданным separator. Если separator является nil, используется текущий $, Если и separator, и $, равны nil, используется пустая строка.

[ "a", "b", "c" ].join        #=> "abc"
[ "a", "b", "c" ].join("-")   #=> "a-b-c"
keep_if { |item| block } → ary Показать исходный код
keep_if → Enumerator
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.

См. также #select!

Если блок не задан, вместо этого возвращается Enumerator.

a = %w{ a b c d e f }
a.keep_if { |v| v =~ /[aeiou]/ }  #=> ["a", "e"]
last → obj or nil Показать исходный код
last(n) → new_ary
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.

См. также #first для обратного эффекта.

a = [ "w", "x", "y", "z" ]
a.last     #=> "z"
a.last(2)  #=> ["y", "z"]
length → int Показать исходный код
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
Также псевдоним: size
map { |item| block } → new_ary Показать исходный код
map → Enumerator
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"]
map! {|item| block } → ary Показать исходный код
map! → Enumerator
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!"]
pack ( aTemplateString ) → aBinaryString Показать исходный код
static VALUE
pack_pack(VALUE ary, VALUE fmt)
{
    static const char nul10[] = "\0\0\0\0\0\0\0\0\0\0";
    static const char spc10[] = "          ";
    const char *p, *pend;
    VALUE res, from, associates = 0;
    char type;
    long len, idx, plen;
    const char *ptr;
    int enc_info = 1;           /* 0 - BINARY, 1 - US-ASCII, 2 - UTF-8 */
#ifdef NATINT_PACK
    int natint;         /* native integer */
#endif
    int integer_size, bigendian_p;

    StringValue(fmt);
    p = RSTRING_PTR(fmt);
    pend = p + RSTRING_LEN(fmt);
    res = rb_str_buf_new(0);

    idx = 0;

#define TOO_FEW (rb_raise(rb_eArgError, toofew), 0)
#define MORE_ITEM (idx < RARRAY_LEN(ary))
#define THISFROM (MORE_ITEM ? RARRAY_AREF(ary, idx) : TOO_FEW)
#define NEXTFROM (MORE_ITEM ? RARRAY_AREF(ary, idx++) : TOO_FEW)

    while (p < pend) {
        int explicit_endian = 0;
        if (RSTRING_PTR(fmt) + RSTRING_LEN(fmt) != pend) {
            rb_raise(rb_eRuntimeError, "format string modified");
        }
        type = *p++;           /* get data type */
#ifdef NATINT_PACK
        natint = 0;
#endif

        if (ISSPACE(type)) continue;
        if (type == '#') {
            while ((p < pend) && (*p != '\n')) {
                p++;
            }
            continue;
        }

        {
          modifiers:
            switch (*p) {
              case '_':
              case '!':
                if (strchr(natstr, type)) {
#ifdef NATINT_PACK
                    natint = 1;
#endif
                    p++;
                }
                else {
                    rb_raise(rb_eArgError, "'%c' allowed only after types %s", *p, natstr);
                }
                goto modifiers;

              case '<':
              case '>':
                if (!strchr(endstr, type)) {
                    rb_raise(rb_eArgError, "'%c' allowed only after types %s", *p, endstr);
                }
                if (explicit_endian) {
                    rb_raise(rb_eRangeError, "Can't use both '<' and '>'");
                }
                explicit_endian = *p++;
                goto modifiers;
            }
        }

        if (*p == '*') {       /* set data length */
            len = strchr("@Xxu", type) ? 0
                : strchr("PMm", type) ? 1
                : RARRAY_LEN(ary) - idx;
            p++;
        }
        else if (ISDIGIT(*p)) {
            errno = 0;
            len = STRTOUL(p, (char**)&p, 10);
            if (errno) {
                rb_raise(rb_eRangeError, "pack length too big");
            }
        }
        else {
            len = 1;
        }

        switch (type) {
          case 'U':
            /* if encoding is US-ASCII, upgrade to UTF-8 */
            if (enc_info == 1) enc_info = 2;
            break;
          case 'm': case 'M': case 'u':
            /* keep US-ASCII (do nothing) */
            break;
          default:
            /* fall back to BINARY */
            enc_info = 0;
            break;
        }
        switch (type) {
          case 'A': case 'a': case 'Z':
          case 'B': case 'b':
          case 'H': case 'h':
            from = NEXTFROM;
            if (NIL_P(from)) {
                ptr = "";
                plen = 0;
            }
            else {
                StringValue(from);
                ptr = RSTRING_PTR(from);
                plen = RSTRING_LEN(from);
                OBJ_INFECT(res, from);
            }

            if (p[-1] == '*')
                len = plen;

            switch (type) {
              case 'a':                /* arbitrary binary string (null padded)  */
              case 'A':         /* arbitrary binary string (ASCII space padded) */
              case 'Z':         /* null terminated string  */
                if (plen >= len) {
                    rb_str_buf_cat(res, ptr, len);
                    if (p[-1] == '*' && type == 'Z')
                        rb_str_buf_cat(res, nul10, 1);
                }
                else {
                    rb_str_buf_cat(res, ptr, plen);
                    len -= plen;
                    while (len >= 10) {
                        rb_str_buf_cat(res, (type == 'A')?spc10:nul10, 10);
                        len -= 10;
                    }
                    rb_str_buf_cat(res, (type == 'A')?spc10:nul10, len);
                }
                break;

#define castchar(from) (char)((from) & 0xff)

              case 'b':                /* bit string (ascending) */
                {
                    int byte = 0;
                    long i, j = 0;

                    if (len > plen) {
                        j = (len - plen + 1)/2;
                        len = plen;
                    }
                    for (i=0; i++ < len; ptr++) {
                        if (*ptr & 1)
                            byte |= 128;
                        if (i & 7)
                            byte >>= 1;
                        else {
                            char c = castchar(byte);
                            rb_str_buf_cat(res, &c, 1);
                            byte = 0;
                        }
                    }
                    if (len & 7) {
                        char c;
                        byte >>= 7 - (len & 7);
                        c = castchar(byte);
                        rb_str_buf_cat(res, &c, 1);
                    }
                    len = j;
                    goto grow;
                }
                break;

              case 'B':                /* bit string (descending) */
                {
                    int byte = 0;
                    long i, j = 0;

                    if (len > plen) {
                        j = (len - plen + 1)/2;
                        len = plen;
                    }
                    for (i=0; i++ < len; ptr++) {
                        byte |= *ptr & 1;
                        if (i & 7)
                            byte <<= 1;
                        else {
                            char c = castchar(byte);
                            rb_str_buf_cat(res, &c, 1);
                            byte = 0;
                        }
                    }
                    if (len & 7) {
                        char c;
                        byte <<= 7 - (len & 7);
                        c = castchar(byte);
                        rb_str_buf_cat(res, &c, 1);
                    }
                    len = j;
                    goto grow;
                }
                break;

              case 'h':                /* hex string (low nibble first) */
                {
                    int byte = 0;
                    long i, j = 0;

                    if (len > plen) {
                        j = (len + 1) / 2 - (plen + 1) / 2;
                        len = plen;
                    }
                    for (i=0; i++ < len; ptr++) {
                        if (ISALPHA(*ptr))
                            byte |= (((*ptr & 15) + 9) & 15) << 4;
                        else
                            byte |= (*ptr & 15) << 4;
                        if (i & 1)
                            byte >>= 4;
                        else {
                            char c = castchar(byte);
                            rb_str_buf_cat(res, &c, 1);
                            byte = 0;
                        }
                    }
                    if (len & 1) {
                        char c = castchar(byte);
                        rb_str_buf_cat(res, &c, 1);
                    }
                    len = j;
                    goto grow;
                }
                break;

              case 'H':                /* hex string (high nibble first) */
                {
                    int byte = 0;
                    long i, j = 0;

                    if (len > plen) {
                        j = (len + 1) / 2 - (plen + 1) / 2;
                        len = plen;
                    }
                    for (i=0; i++ < len; ptr++) {
                        if (ISALPHA(*ptr))
                            byte |= ((*ptr & 15) + 9) & 15;
                        else
                            byte |= *ptr & 15;
                        if (i & 1)
                            byte <<= 4;
                        else {
                            char c = castchar(byte);
                            rb_str_buf_cat(res, &c, 1);
                            byte = 0;
                        }
                    }
                    if (len & 1) {
                        char c = castchar(byte);
                        rb_str_buf_cat(res, &c, 1);
                    }
                    len = j;
                    goto grow;
                }
                break;
            }
            break;

          case 'c':            /* signed char */
          case 'C':            /* unsigned char */
            integer_size = 1;
            bigendian_p = BIGENDIAN_P(); /* not effective */
            goto pack_integer;

          case 's':            /* s for int16_t, s! for signed short */
            integer_size = NATINT_LEN(short, 2);
            bigendian_p = BIGENDIAN_P();
            goto pack_integer;

          case 'S':            /* S for uint16_t, S! for unsigned short */
            integer_size = NATINT_LEN(short, 2);
            bigendian_p = BIGENDIAN_P();
            goto pack_integer;

          case 'i':            /* i and i! for signed int */
            integer_size = (int)sizeof(int);
            bigendian_p = BIGENDIAN_P();
            goto pack_integer;

          case 'I':            /* I and I! for unsigned int */
            integer_size = (int)sizeof(int);
            bigendian_p = BIGENDIAN_P();
            goto pack_integer;

          case 'l':            /* l for int32_t, l! for signed long */
            integer_size = NATINT_LEN(long, 4);
            bigendian_p = BIGENDIAN_P();
            goto pack_integer;

          case 'L':            /* L for uint32_t, L! for unsigned long */
            integer_size = NATINT_LEN(long, 4);
            bigendian_p = BIGENDIAN_P();
            goto pack_integer;

          case 'q':            /* q for int64_t, q! for signed long long */
            integer_size = NATINT_LEN_Q;
            bigendian_p = BIGENDIAN_P();
            goto pack_integer;

          case 'Q':            /* Q for uint64_t, Q! for unsigned long long */
            integer_size = NATINT_LEN_Q;
            bigendian_p = BIGENDIAN_P();
            goto pack_integer;

          case 'j':            /* j for intptr_t */
            integer_size = sizeof(intptr_t);
            bigendian_p = BIGENDIAN_P();
            goto pack_integer;

          case 'J':            /* J for uintptr_t */
            integer_size = sizeof(uintptr_t);
            bigendian_p = BIGENDIAN_P();
            goto pack_integer;

          case 'n':            /* 16 bit (2 bytes) integer (network byte-order)  */
            integer_size = 2;
            bigendian_p = 1;
            goto pack_integer;

          case 'N':            /* 32 bit (4 bytes) integer (network byte-order) */
            integer_size = 4;
            bigendian_p = 1;
            goto pack_integer;

          case 'v':            /* 16 bit (2 bytes) integer (VAX byte-order) */
            integer_size = 2;
            bigendian_p = 0;
            goto pack_integer;

          case 'V':            /* 32 bit (4 bytes) integer (VAX byte-order) */
            integer_size = 4;
            bigendian_p = 0;
            goto pack_integer;

          pack_integer:
            if (explicit_endian) {
                bigendian_p = explicit_endian == '>';
            }
            if (integer_size > MAX_INTEGER_PACK_SIZE)
                rb_bug("unexpected intger size for pack: %d", integer_size);
            while (len-- > 0) {
                char intbuf[MAX_INTEGER_PACK_SIZE];

                from = NEXTFROM;
                rb_integer_pack(from, intbuf, integer_size, 1, 0,
                    INTEGER_PACK_2COMP |
                    (bigendian_p ? INTEGER_PACK_BIG_ENDIAN : INTEGER_PACK_LITTLE_ENDIAN));
                rb_str_buf_cat(res, intbuf, integer_size);
            }
            break;

          case 'f':            /* single precision float in native format */
          case 'F':            /* ditto */
            while (len-- > 0) {
                float f;

                from = NEXTFROM;
                f = (float)RFLOAT_VALUE(rb_to_float(from));
                rb_str_buf_cat(res, (char*)&f, sizeof(float));
            }
            break;

          case 'e':            /* single precision float in VAX byte-order */
            while (len-- > 0) {
                FLOAT_CONVWITH(tmp);

                from = NEXTFROM;
                tmp.f = (float)RFLOAT_VALUE(rb_to_float(from));
                HTOVF(tmp);
                rb_str_buf_cat(res, tmp.buf, sizeof(float));
            }
            break;

          case 'E':            /* double precision float in VAX byte-order */
            while (len-- > 0) {
                DOUBLE_CONVWITH(tmp);
                from = NEXTFROM;
                tmp.d = RFLOAT_VALUE(rb_to_float(from));
                HTOVD(tmp);
                rb_str_buf_cat(res, tmp.buf, sizeof(double));
            }
            break;

          case 'd':            /* double precision float in native format */
          case 'D':            /* ditto */
            while (len-- > 0) {
                double d;

                from = NEXTFROM;
                d = RFLOAT_VALUE(rb_to_float(from));
                rb_str_buf_cat(res, (char*)&d, sizeof(double));
            }
            break;

          case 'g':            /* single precision float in network byte-order */
            while (len-- > 0) {
                FLOAT_CONVWITH(tmp);
                from = NEXTFROM;
                tmp.f = (float)RFLOAT_VALUE(rb_to_float(from));
                HTONF(tmp);
                rb_str_buf_cat(res, tmp.buf, sizeof(float));
            }
            break;

          case 'G':            /* double precision float in network byte-order */
            while (len-- > 0) {
                DOUBLE_CONVWITH(tmp);

                from = NEXTFROM;
                tmp.d = RFLOAT_VALUE(rb_to_float(from));
                HTOND(tmp);
                rb_str_buf_cat(res, tmp.buf, sizeof(double));
            }
            break;

          case 'x':            /* null byte */
          grow:
            while (len >= 10) {
                rb_str_buf_cat(res, nul10, 10);
                len -= 10;
            }
            rb_str_buf_cat(res, nul10, len);
            break;

          case 'X':            /* back up byte */
          shrink:
            plen = RSTRING_LEN(res);
            if (plen < len)
                rb_raise(rb_eArgError, "X outside of string");
            rb_str_set_len(res, plen - len);
            break;

          case '@':            /* null fill to absolute position */
            len -= RSTRING_LEN(res);
            if (len > 0) goto grow;
            len = -len;
            if (len > 0) goto shrink;
            break;

          case '%':
            rb_raise(rb_eArgError, "%% is not supported");
            break;

          case 'U':            /* Unicode character */
            while (len-- > 0) {
                SIGNED_VALUE l;
                char buf[8];
                int le;

                from = NEXTFROM;
                from = rb_to_int(from);
                l = NUM2LONG(from);
                if (l < 0) {
                    rb_raise(rb_eRangeError, "pack(U): value out of range");
                }
                le = rb_uv_to_utf8(buf, l);
                rb_str_buf_cat(res, (char*)buf, le);
            }
            break;

          case 'u':            /* uuencoded string */
          case 'm':            /* base64 encoded string */
            from = NEXTFROM;
            StringValue(from);
            ptr = RSTRING_PTR(from);
            plen = RSTRING_LEN(from);
            OBJ_INFECT(res, from);

            if (len == 0 && type == 'm') {
                encodes(res, ptr, plen, type, 0);
                ptr += plen;
                break;
            }
            if (len <= 2)
                len = 45;
            else if (len > 63 && type == 'u')
                len = 63;
            else
                len = len / 3 * 3;
            while (plen > 0) {
                long todo;

                if (plen > len)
                    todo = len;
                else
                    todo = plen;
                encodes(res, ptr, todo, type, 1);
                plen -= todo;
                ptr += todo;
            }
            break;

          case 'M':            /* quoted-printable encoded string */
            from = rb_obj_as_string(NEXTFROM);
            OBJ_INFECT(res, from);
            if (len <= 1)
                len = 72;
            qpencode(res, from, len);
            break;

          case 'P':            /* pointer to packed byte string */
            from = THISFROM;
            if (!NIL_P(from)) {
                StringValue(from);
                if (RSTRING_LEN(from) < len) {
                    rb_raise(rb_eArgError, "too short buffer for P(%ld for %ld)",
                             RSTRING_LEN(from), len);
                }
            }
            len = 1;
            /* FALL THROUGH */
          case 'p':            /* pointer to string */
            while (len-- > 0) {
                char *t;
                from = NEXTFROM;
                if (NIL_P(from)) {
                    t = 0;
                }
                else {
                    t = StringValuePtr(from);
                    OBJ_INFECT(res, from);
                    rb_obj_taint(from);
                }
                if (!associates) {
                    associates = rb_ary_new();
                }
                rb_ary_push(associates, from);
                rb_str_buf_cat(res, (char*)&t, sizeof(char*));
            }
            break;

          case 'w':            /* BER compressed integer  */
            while (len-- > 0) {
                VALUE buf = rb_str_new(0, 0);
                size_t numbytes;
                int sign;
                char *cp;

                from = NEXTFROM;
                from = rb_to_int(from);
                numbytes = rb_absint_numwords(from, 7, NULL);
                if (numbytes == 0)
                    numbytes = 1;
                buf = rb_str_new(NULL, numbytes);

                sign = rb_integer_pack(from, RSTRING_PTR(buf), RSTRING_LEN(buf), 1, 1, INTEGER_PACK_BIG_ENDIAN);

                if (sign < 0)
                    rb_raise(rb_eArgError, "can't compress negative numbers");
                if (sign == 2)
                    rb_bug("buffer size problem?");

                cp = RSTRING_PTR(buf);
                while (1 < numbytes) {
                  *cp |= 0x80;
                  cp++;
                  numbytes--;
                }

                rb_str_buf_cat(res, RSTRING_PTR(buf), RSTRING_LEN(buf));
            }
            break;

          default: {
            char unknown[5];
            if (ISPRINT(type)) {
                unknown[0] = type;
                unknown[1] = '\0';
            }
            else {
                snprintf(unknown, sizeof(unknown), "\\x%.2x", type & 0xff);
            }
            rb_warning("unknown pack directive '%s' in '% "PRIsVALUE"'",
                       unknown, fmt);
            break;
          }
        }
    }

    if (associates) {
        str_associate(res, associates);
    }
    OBJ_INFECT(res, fmt);
    switch (enc_info) {
      case 1:
        ENCODING_CODERANGE_SET(res, rb_usascii_encindex(), ENC_CODERANGE_7BIT);
        break;
      case 2:
        rb_enc_set_index(res, rb_utf8_encindex());
        break;
      default:
        /* do nothing, keep ASCII-8BIT */
        break;
    }
    return res;
}

Упаковывает содержимое arr в двоичную последовательность в соответствии с указаниями в aTemplateString (см. таблицу ниже) Директивы “A,'' “a,'' и “Z'' могут сопровождаться числом, которое задаёт ширину результирующего поля. Остальные директивы также могут принимать число, указывающее количество элементов массива для преобразования. Если число является звёздочкой (“*''), будут преобразованы все оставшиеся элементы массива. Любая из директив “sSiIlL'' может быть после underscore (“_'') или восклицательного знака (“!'') для использования родного размера платформы для указанного типа; в противном случае используется платформенно-независимый размер. Пробелы игнорируются в строке шаблона. См. также 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"

Директивы для 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> L> Q>  | Integer | same as the directives without ">" except
   J> s> l>  |         | big endian
   q> j>     |         | (available since Ruby 1.9.3)
   S!> I!>   |         | "S>" is same as "n"
   L!> Q!>   |         | "L>" is same as "N"
   J!> s!>   |         |
   i!> l!>   |         |
   q!> j!>   |         |
             |         |
   S< L< Q<  | Integer | same as the directives without "<" except
   J< s< l<  |         | little endian
   q< j<     |         | (available since Ruby 1.9.3)
   S!< I!<   |         | "S<" is same as "v"
   L!< Q!<   |         | "L<" is same as "V"
   J!< s!<   |         |
   i!< l!<   |         |
   q!< j!<   |         |
             |         |
   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        |         |
Directive    |         | 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       |         |
Directive    |         | 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 RFC2045)
   m         | String  | base64 encoded string (see RFC 2045, count is width)
             |         | (if count is 0, no line feed are added, see RFC 4648)
   P         | String  | pointer to a structure (fixed-length string)
   p         | String  | pointer to a null-terminated string

Misc.        |         |
Directive    |         | Meaning
---------------------------------------------------------------------------
   @         | ---     | moves to absolute position
   X         | ---     | back up a byte
   x         | ---     | null byte
permutation { |p| block } → ary Показать исходный код
permutation → Enumerator
permutation(n) { |p| block } → ary
permutation(n) → Enumerator
static VALUE
rb_ary_permutation(int argc, VALUE *argv, VALUE ary)
{
    VALUE num;
    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 */
    rb_scan_args(argc, argv, "01", &num);
    r = NIL_P(num) ? n : NUM2LONG(num);   /* 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
pop → obj or nil Показать исходный код
pop(n) → new_ary
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));
    return result;
}

Удаляет последний элемент из self и возвращает его, или nil если массив пуст.

Если задано число n, возвращает массив из последних n элементов (или меньше), точно так же как и array.slice!(-n, n). См. также #push для обратного эффекта.

a = [ "a", "b", "c", "d" ]
a.pop     #=> "d"
a.pop(2)  #=> ["b", "c"]
a         #=> ["a"]
product(other_ary, ...) → new_ary Показать исходный код
product(other_ary, ...) { |p| block } → ary
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 = tmpbuf(n, sizeof(int));
    VALUE *arrays = RARRAY_PTR(t0); /* The arrays we're computing the product of */
    int *counters = (int*)RSTRING_PTR(t1); /* 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);
    RBASIC_CLEAR_CLASS(t1);

    /* 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);
    tmpbuf_discard(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([])          #=> []
END_OF_DOCUMENT_MARKER
push(obj, ... ) → ary Show source
static VALUE
rb_ary_push_m(int argc, VALUE *argv, VALUE ary)
{
    return rb_ary_cat(ary, argv, argc);
}

Добавить — Добавляет заданный объект(ы) в конец этого массива. Это выражение возвращает сам массив, поэтому несколько добавлений могут быть объединены в цепочку. См. также #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]
rassoc(obj) → element_ary or nil Show source
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.

См. также #assoc.

a = [ [ 1, "one"], [2, "two"], [3, "three"], ["ii", "two"] ]
a.rassoc("two")    #=> [2, "two"]
a.rassoc("four")   #=> nil
reject {|item| block } → new_ary Show source
reject → Enumerator
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.

Порядок неотвергнутых элементов сохраняется.

См. также #delete_if

Если блок не задан, вместо этого возвращается Enumerator.

reject! { |item| block } → ary or nil Show source
reject! → Enumerator
static VALUE
rb_ary_reject_bang(VALUE ary)
{
    RETURN_SIZED_ENUMERATOR(ary, 0, 0, ary_enum_length);
    return ary_reject_bang(ary);
}

Удаляет каждый элемент из self, для которого блок вычисляется как true, если изменений не было, возвращает nil.

Массив может не изменяться мгновенно каждый раз, когда вызывается блок.

См. также Enumerable#reject и #delete_if.

Если блок не задан, вместо этого возвращается Enumerator.

repeated_combination(n) { |c| block } → ary Show source
repeated_combination(n) → 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
repeated_permutation(n) { |p| block } → ary Show source
repeated_permutation(n) → Enumerator
static VALUE
rb_ary_repeated_permutation(VALUE ary, VALUE num)
{
    long r, n, i;

    n = RARRAY_LEN(ary);                  /* Array length */
    RETURN_SIZED_ENUMERATOR(ary, 1, &num, rb_ary_repeated_permutation_size);      /* Return Enumerator if no block */
    r = NUM2LONG(num);                    /* Permutation size from argument */

    if (r < 0) {
        /* no permutations: yield nothing */
    }
    else if (r == 0) { /* exactly one permutation: the zero-length array */
        rb_yield(rb_ary_new2(0));
    }
    else if (r == 1) { /* this is a special, easy case */
        for (i = 0; i < RARRAY_LEN(ary); i++) {
            rb_yield(rb_ary_new3(1, RARRAY_AREF(ary, i)));
        }
    }
    else {             /* this is the general case */
        volatile VALUE t0;
        long *p = ALLOCV_N(long, t0, r);
        VALUE ary0 = ary_make_shared_copy(ary); /* private defensive copy of ary */
        RBASIC_CLEAR_CLASS(ary0);

        rpermute0(n, r, p, ary0); /* compute and yield repeated permutations */
        ALLOCV_END(t0);
        RBASIC_SET_CLASS_RAW(ary0, rb_cArray);
    }
    return ary;
}

При вызове с блоком создаёт все повторяющиеся перестановки длиной 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
replace(other_ary) → ary Show source
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 = 0;

        if (ARY_OWNS_HEAP_P(copy)) {
            RARRAY_PTR_USE(copy, ptr, ruby_sized_xfree(ptr, ARY_HEAP_SIZE(copy)));
        }
        else if (ARY_SHARED_P(copy)) {
            shared = ARY_SHARED(copy);
            FL_UNSET_SHARED(copy);
        }
        FL_SET_EMBED(copy);
        ary_memcpy(copy, 0, RARRAY_LEN(orig), RARRAY_CONST_PTR(orig));
        if (shared) {
            rb_ary_decrement_share(shared);
        }
        ARY_SET_LEN(copy, RARRAY_LEN(orig));
    }
    else {
        VALUE shared = ary_make_shared(orig);
        if (ARY_OWNS_HEAP_P(copy)) {
            RARRAY_PTR_USE(copy, ptr, ruby_sized_xfree(ptr, ARY_HEAP_SIZE(copy)));
        }
        else {
            rb_ary_unshare_safe(copy);
        }
        FL_UNSET_EMBED(copy);
        ARY_SET_PTR(copy, RARRAY_CONST_PTR(orig));
        ARY_SET_LEN(copy, RARRAY_LEN(orig));
        rb_ary_set_shared(copy, shared);
    }
    return copy;
}

Заменяет содержимое self содержимым other_ary, усекая или расширяя при необходимости.

a = [ "a", "b", "c", "d", "e" ]
a.replace([ "x", "y", "z" ])   #=> ["x", "y", "z"]
a                              #=> ["x", "y", "z"]
reverse → new_ary Show source
static VALUE
rb_ary_reverse_m(VALUE ary)
{
    long len = RARRAY_LEN(ary);
    VALUE dup = rb_ary_new2(len);

    if (len > 0) {
        const VALUE *p1 = RARRAY_CONST_PTR(ary);
        VALUE *p2 = (VALUE *)RARRAY_CONST_PTR(dup) + len - 1;
        do *p2-- = *p1++; while (--len > 0);
    }
    ARY_SET_LEN(dup, RARRAY_LEN(ary));
    return dup;
}

Возвращает новый массив, содержащий элементы self в обратном порядке.

[ "a", "b", "c" ].reverse   #=> ["c", "b", "a"]
[ 1 ].reverse               #=> [1]
reverse! → ary Show source
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"]
reverse_each { |item| block } → ary Show source
reverse_each → Enumerator
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;
}

То же, что и #each, но проходит по self в обратном порядке.

a = [ "a", "b", "c" ]
a.reverse_each {|x| print x, " " }

производит:

c b a
rindex(obj) → int or nil Show source
rindex { |item| block } → int or nil
rindex → Enumerator
static VALUE
rb_ary_rindex(int argc, VALUE *argv, VALUE ary)
{
    const VALUE *ptr;
    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");
    ptr = RARRAY_CONST_PTR(ary);
    while (i--) {
        VALUE e = ptr[i];
        switch (rb_equal_opt(e, val)) {
          case Qundef:
            if (!rb_equal(e, val)) break;
          case Qtrue:
            return LONG2NUM(i);
          case Qfalse:
            continue;
        }
        if (i > (len = RARRAY_LEN(ary))) {
            i = len;
        }
        ptr = RARRAY_CONST_PTR(ary);
    }
    return Qnil;
}

Возвращает индекс последнего объекта в self == к obj.

Если вместо аргумента задан блок, возвращает индекс первого объекта, для которого блок возвращает true, начиная с последнего объекта.

Возвращает nil, если совпадений не найдено.

См. также #index.

Если не задан ни блок, ни аргумент, вместо этого возвращается Enumerator.

a = [ "a", "b", "b", "b", "c" ]
a.rindex("b")             #=> 3
a.rindex("z")             #=> nil
a.rindex { |x| x == "b" } #=> 3
rotate(count=1) → new_ary Show source
static VALUE
rb_ary_rotate_m(int argc, VALUE *argv, VALUE ary)
{
    VALUE rotated;
    const VALUE *ptr;
    long len, cnt = 1;

    switch (argc) {
      case 1: cnt = NUM2LONG(argv[0]);
      case 0: break;
      default: rb_scan_args(argc, argv, "01", NULL);
    }

    len = RARRAY_LEN(ary);
    rotated = rb_ary_new2(len);
    if (len > 0) {
        cnt = rotate_count(cnt, len);
        ptr = RARRAY_CONST_PTR(ary);
        len -= cnt;
        ary_memcpy(rotated, 0, len, ptr + cnt);
        ary_memcpy(rotated, len, cnt, ptr);
    }
    ARY_SET_LEN(rotated, RARRAY_LEN(ary));
    return rotated;
}

Возвращает новый массив, вращая self, так что элемент в count становится первым элементом нового массива.

Если 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"]
rotate!(count=1) → ary Show source
static VALUE
rb_ary_rotate_bang(int argc, VALUE *argv, VALUE ary)
{
    long n = 1;

    switch (argc) {
      case 1: n = NUM2LONG(argv[0]);
      case 0: break;
      default: rb_scan_args(argc, argv, "01", NULL);
    }
    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"]
sample → obj Show source
sample(random: rng) → obj
sample(n) → new_ary
sample(n, random: rng) → new_ary
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)];

    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 (argc == 0) {
        if (len < 2)
            i = 0;
        else
            i = RAND_UPTO(len);

        return rb_ary_elt(ary, i);
    }
    rb_scan_args(argc, argv, "1", &nv);
    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));
    }
    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(result, ptr_result, {
            for (i=0; i<n; i++) {
                ptr_result[i] = RARRAY_AREF(ary, idx[i]);
            }
        });
    }
    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, а вторая форма возвращает пустой массив.

Необязательный аргумент rng будет использоваться в качестве генератора случайных чисел.

a = [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ]
a.sample         #=> 7
a.sample(4)      #=> [6, 4, 2, 5]
select { |item| block } → new_ary Show source
select → Enumerator
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.

select! {|item| block } → ary or nil Показать исходный код
select! → Enumerator
static VALUE
rb_ary_select_bang(VALUE ary)
{
    struct select_bang_arg args;

    RETURN_SIZED_ENUMERATOR(ary, 0, 0, ary_enum_length);
    rb_ary_modify(ary);

    args.ary = ary;
    args.len[0] = args.len[1] = 0;
    return rb_ensure(select_bang_i, (VALUE)&args, select_bang_ensure, (VALUE)&args);
}

Вызывает переданный блок, передавая в него последовательные элементы из self, удаляя элементы, для которых блок возвращает false значение.

Массив может не изменяться мгновенно каждый раз при вызове блока.

Если изменения были внесены, возвращается self, в противном случае возвращается nil.

См. также #keep_if

Если блок не указан, вместо него возвращается Enumerator.

shelljoin → string Показать исходный код
# File lib/shellwords.rb, line 220
def shelljoin
  Shellwords.join(self)
end

Строит строку командной строки из списка аргументов array, объединяя все элементы, экранированные для оболочки Bourne, и отделяя их пробелами.

См. Shellwords#shelljoin для подробностей.

shift → obj or nil Показать исходный код
shift(n) → new_ary
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);
    if (ARY_SHARED_P(ary)) {
        if (ARY_SHARED_OCCUPIED(ARY_SHARED(ary))) {
          setup_occupied_shared:
            ary_mem_clear(ary, 0, n);
        }
        ARY_INCREASE_PTR(ary, n);
    }
    else {
        if (RARRAY_LEN(ary) < ARY_DEFAULT_SIZE) {
            RARRAY_PTR_USE(ary, ptr, {
                MEMMOVE(ptr, ptr+n, VALUE, RARRAY_LEN(ary)-n);
            }); /* WB: no new reference */
        }
        else {
            ary_make_shared(ary);
            goto setup_occupied_shared;
        }
    }
    ARY_INCREASE_LEN(ary, -n);

    return result;
}

Удаляет первый элемент из self и возвращает его (сдвигая все остальные элементы вниз на одну позицию). Возвращает nil если массив пустой.

Если задано число n, возвращает массив из первых n элементов (или меньше), точно так же, как и array.slice!(0, n). При этом в ary остаются только оставшиеся элементы, не включая то, что было сдвинуто в new_ary. См. также #unshift для противоположного эффекта.

args = [ "-m", "-q", "filename" ]
args.shift     #=> "-m"
args           #=> ["-q", "filename"]

args = [ "-m", "-q", "filename" ]
args.shift(2)  #=> ["-m", "-q"]
args           #=> ["filename"]
shuffle → new_ary Показать исходный код
shuffle(random: rng) → new_ary
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]
shuffle! → ary Показать исходный код
shuffle!(random: rng) → ary
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(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]
size()
Псевдоним для: length
slice(index) → obj or nil Показать исходный код
slice(start, length) → new_ary or nil
slice(range) → new_ary or nil
VALUE
rb_ary_aref(int argc, const VALUE *argv, VALUE ary)
{
    VALUE arg;
    long beg, len;

    if (argc == 2) {
        beg = NUM2LONG(argv[0]);
        len = NUM2LONG(argv[1]);
        if (beg < 0) {
            beg += RARRAY_LEN(ary);
        }
        return rb_ary_subseq(ary, beg, len);
    }
    if (argc != 1) {
        rb_scan_args(argc, argv, "11", NULL, NULL);
    }
    arg = argv[0];
    /* special case - speeding up */
    if (FIXNUM_P(arg)) {
        return rb_ary_entry(ary, FIX2LONG(arg));
    }
    /* check if idx is Range */
    switch (rb_range_beg_len(arg, &beg, &len, RARRAY_LEN(ary), 0)) {
      case Qfalse:
        break;
      case Qnil:
        return Qnil;
      default:
        return rb_ary_subseq(ary, beg, len);
    }
    return rb_ary_entry(ary, NUM2LONG(arg));
}

Ссылка на элемент — Возвращает элемент по 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]               #=> []
slice!(index) → obj or nil Показать исходный код
slice!(start, length) → new_ary or nil
slice!(range) → new_ary or nil
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(ary)+pos);
        RBASIC_SET_CLASS(arg2, rb_obj_class(ary));
        rb_ary_splice(ary, pos, len, Qundef);
        return arg2;
    }

    if (argc != 1) {
        /* error report */
        rb_scan_args(argc, argv, "11", NULL, NULL);
    }
    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"]
sort → new_ary Показать исходный код
sort { |a, b| block } → new_ary
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.

См. также Enumerable#sort_by.

a = [ "d", "a", "e", "c", "b" ]
a.sort                    #=> ["a", "b", "c", "d", "e"]
a.sort { |x,y| y <=> x }  #=> ["e", "d", "c", "b", "a"]
sort! → ary Показать исходный код
sort! { |a, b| block } → ary
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.opt_methods = 0;
        data.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 {
                    ruby_sized_xfree((void *)ARY_HEAP_PTR(ary), ARY_HEAP_SIZE(ary));
                }
                ARY_SET_PTR(ary, RARRAY_CONST_PTR(tmp));
                ARY_SET_HEAP_LEN(ary, len);
                ARY_SET_CAPA(ary, RARRAY_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 */
    }
    return ary;
}

Сортирует self на месте.

Сравнения для сортировки будут выполняться с использованием <=> оператора или с использованием необязательного блока кода.

Блок должен реализовывать сравнение между a и b и возвращать целое число меньше 0, когда b следует за a, 0 когда a и b эквивалентны, или целое число больше 0, когда a следует за b.

См. также Enumerable#sort_by.

a = [ "d", "a", "e", "c", "b" ]
a.sort!                    #=> ["a", "b", "c", "d", "e"]
a.sort! { |x,y| y <=> x }  #=> ["e", "d", "c", "b", "a"]
sort_by! { |obj| block } → ary Показать исходный код
sort_by! → Enumerator
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.

take(n) → new_ary Показать исходный код
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.

См. также #drop

a = [1, 2, 3, 4, 5, 0]
a.take(3)             #=> [1, 2, 3]
take_while { |obj| block } → new_ary Показать исходный код
take_while → Enumerator
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.

См. также #drop_while

a = [1, 2, 3, 4, 5, 0]
a.take_while { |i| i < 3 }  #=> [1, 2]
to_a → ary Показать исходный код
static VALUE
rb_ary_to_a(VALUE ary)
{
    if (rb_obj_class(ary) != rb_cArray) {
        VALUE dup = rb_ary_new2(RARRAY_LEN(ary));
        rb_ary_replace(dup, ary);
        return dup;
    }
    return ary;
}

Возвращает self.

Если вызывается на подклассе Array, преобразует получателя в объект Array.

to_ary → ary Показать исходный код
static VALUE
rb_ary_to_ary_m(VALUE ary)
{
    return ary;
}

Возвращает self.

to_h → hash Показать исходный код
static VALUE
rb_ary_to_h(VALUE ary)
{
    long i;
    VALUE hash = rb_hash_new();
    for (i=0; i<RARRAY_LEN(ary); i++) {
        const VALUE elt = rb_ary_elt(ary, i);
        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}
END_OF_DOCUMENT_MARKER
to_s()
Псевдоним для: inspect
transpose → new_ary Показать исходный код
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.

uniq → new_ary Показать исходный код
uniq { |item| ... } → new_ary
static VALUE
rb_ary_uniq(VALUE ary)
{
    VALUE hash, uniq;

    if (RARRAY_LEN(ary) <= 1)
        return rb_ary_dup(ary);
    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));
    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"]]
uniq! → ary or nil Показать исходный код
uniq! { |item| ... } → ary or nil
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);
    st_foreach(rb_hash_tbl_raw(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"]]
unshift(obj, ...) → ary Показать исходный код
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, перемещая другие элементы вверх. См. также #shift для обратного действия.

a = [ "b", "c", "d" ]
a.unshift("a")   #=> ["a", "b", "c", "d"]
a.unshift(1, 2)  #=> [ 1, 2, "a", "b", "c", "d"]
values_at(selector, ...) → new_ary Показать исходный код
static VALUE
rb_ary_values_at(int argc, VALUE *argv, VALUE ary)
{
    return rb_get_values_at(ary, RARRAY_LEN(ary), argc, argv, rb_ary_entry);
}

Возвращает массив, содержащий элементы self соответствующие заданным selector.

Селекторы могут быть целочисленными индексами или диапазонами.

См. также #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"]
zip(arg, ...) → new_ary Показать исходный код
zip(arg, ...) { |arr| block } → nil
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]]
ary | other_ary → new_ary Показать исходный код
static VALUE
rb_ary_or(VALUE ary1, VALUE ary2)
{
    VALUE hash, ary3;
    long i;

    ary2 = to_ary(ary2);
    hash = ary_make_hash(ary1);

    for (i=0; i<RARRAY_LEN(ary2); i++) {
        VALUE elt = RARRAY_AREF(ary2, i);
        if (!st_update(RHASH_TBL_RAW(hash), (st_data_t)elt, ary_hash_orset, (st_data_t)elt)) {
            RB_OBJ_WRITTEN(hash, Qundef, elt);
        }
    }
    ary3 = rb_hash_values(hash);
    ary_recycle_hash(hash);
    return ary3;
}

Объединение множеств — возвращает новый массив, объединяя ary с other_ary, исключая дубликаты и сохраняя порядок из исходного массива.

Для повышения эффективности сравнение элементов выполняется с использованием методов hash и eql?.

[ "a", "b", "c" ] | [ "c", "d", "a" ]    #=> [ "a", "b", "c", "d" ]

См. также #uniq.

Ruby Core © 1993–2017 Yukihiro Matsumoto
Licensed under the Ruby License.
Ruby Standard Library © contributors
Licensed under their own licenses.

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API