Spec-Zone.ru › Ruby 2.4

класс 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 ] & [ 3, 2, 1 ]                 #=> [ 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;
}

Повторение — С строковым аргументом, эквивалентно 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 or 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;
    VALUE rpl;

    if (argc == 3) {
        rb_ary_modify_check(ary);
        beg = NUM2LONG(argv[0]);
        len = NUM2LONG(argv[1]);
        goto range;
    }
    rb_check_arity(argc, 2, 2);
    rb_ary_modify_check(ary);
    if (FIXNUM_P(argv[0])) {
        offset = FIX2LONG(argv[0]);
        goto fixnum;
    }
    if (rb_range_beg_len(argv[0], &beg, &len, RARRAY_LEN(ary), 1)) {
        /* check if idx is Range */
      range:
        rpl = rb_ary_to_ary(argv[argc-1]);
        rb_ary_splice(ary, beg, len, RARRAY_CONST_PTR(rpl), RARRAY_LEN(rpl));
        RB_GC_GUARD(rpl);
        return argv[argc-1];
    }

    offset = NUM2LONG(argv[0]);
fixnum:
    rb_ary_store(ary, offset, argv[1]);
    return argv[1];
}

Присвоение элемента — Устанавливает элемент по index, или заменяет подмассив с start индекса для length элементов, или заменяет подмассив, заданный range индексов.

Если индексы превышают текущую емкость массива, массив автоматически увеличивается. Элементы вставляются в массив по start если length равно нулю.

Отрицательные индексы отсчитываются от конца массива. В случаях start и range начальный индекс находится непосредственно перед элементом.

Исключение IndexError выбрасывается, если отрицательный индекс указывает на позицию за началом массива.

См. также #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 128
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 Show source
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 Show source
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 Show source
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 Show source
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 Show source
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 Show source
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 Show source
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 Show source
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_ary1, other_ary2,...) → ary Show source
static VALUE
rb_ary_concat_multi(int argc, VALUE *argv, VALUE ary)
{
    rb_ary_modify_check(ary);

    if (argc > 0) {
        int i;
        VALUE args = rb_ary_tmp_new(argc);
        for (i = 0; i < argc; i++) {
            rb_ary_concat(args, argv[i]);
        }
        ary_append(ary, args);
    }

    return ary;
}

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

[ "a", "b" ].concat( ["c", "d"] ) #=> [ "a", "b", "c", "d" ]
[ "a" ].concat( ["b"], ["c", "d"] ) #=> [ "a", "b", "c", "d" ]
[ "a" ].concat #=> [ "a" ]

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

a = [ 1, 2 ]
a.concat(a, a)                    #=> [1, 2, 1, 2, 1, 2]

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

count → int Show source
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 Show source
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() Show source
# File lib/rexml/xpath_parser.rb, line 32
def dclone
  klone = self.clone
  klone.clear
  self.each{|v| klone << v.dclone}
  klone
end

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

delete(obj) → item or nil Show source
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 Show source
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 Show source
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)                    #=> TypeError: Integer does not have #dig method
[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 = Qundef, arg1, arg2;
    long beg = 0, end = 0, len = 0;

    if (rb_block_given_p()) {
        rb_scan_args(argc, argv, "02", &arg1, &arg2);
        argc += 1;             /* hackish */
    }
    else {
        rb_scan_args(argc, argv, "12", &item, &arg1, &arg2);
    }
    switch (argc) {
      case 1:
        beg = 0;
        len = RARRAY_LEN(ary);
        break;
      case 2:
        if (rb_range_beg_len(arg1, &beg, &len, RARRAY_LEN(ary), 1)) {
            break;
        }
        /* fall through */
      case 3:
        beg = NIL_P(arg1) ? 0 : NUM2LONG(arg1);
        if (beg < 0) {
            beg = RARRAY_LEN(ary) + beg;
            if (beg < 0) beg = 0;
        }
        len = NIL_P(arg2) ? RARRAY_LEN(ary) - beg : NUM2LONG(arg2);
        break;
    }
    rb_ary_modify(ary);
    if (len < 0) {
        return ary;
    }
    if (beg >= ARY_MAX_SIZE || len > ARY_MAX_SIZE - beg) {
        rb_raise(rb_eArgError, "argument too big");
    }
    end = beg + len;
    if (RARRAY_LEN(ary) < end) {
        if (end >= ARY_CAPA(ary)) {
            ary_resize_capa(ary, end);
        }
        ary_mem_clear(ary, RARRAY_LEN(ary), end - RARRAY_LEN(ary));
        ARY_SET_LEN(ary, end);
    }

    if (item == Qundef) {
        VALUE v;
        long i;

        for (i=beg; i<end; i++) {
            v = rb_yield(LONG2NUM(i));
            if (i>=RARRAY_LEN(ary)) break;
            ARY_SET(ary, i, v);
        }
    }
    else {
        ary_memfill(ary, beg, len, item);
    }
    return ary;
}

Первые три формы устанавливают выбранные элементы self (которые могут быть всем массивом) в значение obj.

Значение start nil равно нулю.

Значение length nil равно длине массива.

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

Отрицательные значения start считаются с конца массива, где -1 — последний элемент.

a = [ "a", "b", "c", "d" ]
a.fill("x")              #=> ["x", "x", "x", "x"]
a.fill("z", 2, 2)        #=> ["x", "x", "z", "z"]
a.fill("y", 0..1)        #=> ["y", "y", "z", "z"]
a.fill { |i| i*i }       #=> [0, 1, 4, 9]
a.fill(-2) { |i| i*i*i } #=> [0, 1, 8, 27]
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 → integer Показать исходный код
static VALUE
rb_ary_hash(VALUE ary)
{
    long i;
    st_index_t h;
    VALUE n;

    h = rb_hash_start(RARRAY_LEN(ary));
    h = rb_hash_uint(h, (st_index_t)rb_ary_hash);
    for (i=0; i<RARRAY_LEN(ary); i++) {
        n = rb_hash(RARRAY_AREF(ary, i));
        h = rb_hash_uint(h, NUM2LONG(n));
    }
    h = rb_hash_end(h);
    return ST2FIX(h);
}

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

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

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

END_OF_DOCUMENT_MARKER
include?(object) → true или 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 или nil Показать исходный код
index { |item| блок } → int или 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, argv + 1, argc - 1);
    return ary;
}

Вставляет заданные значения перед элементом с заданным index.

Отрицательные индексы отсчитываются от конца массива, где -1 — последний элемент. Если используется отрицательный индекс, заданные значения будут вставлены после этого элемента, поэтому использование индекса -1 вставит значения в конец массива.

a = %w{ a b c d }
a.insert(2, 99)         #=> ["a", "b", 99, "c", "d"]
a.insert(-2, 1, 2, 3)   #=> ["a", "b", 99, "c", 1, 2, 3, "d"]
inspect → строка Показать исходный код
to_s → строка
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| блок } → 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 или 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| блок } → 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| блок } → 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!"]
max → obj Показать исходный код
max { |a, b| блок } → obj
max(n) → массив
max(n) { |a, b| блок } → массив
static VALUE
rb_ary_max(int argc, VALUE *argv, VALUE ary)
{
    struct cmp_opt_data cmp_opt = { 0, 0 };
    VALUE result = Qundef, v;
    VALUE num;
    long i;

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

    if (!NIL_P(num))
       return rb_nmin_run(ary, num, 0, 1, 1);

    if (rb_block_given_p()) {
        for (i = 0; i < RARRAY_LEN(ary); i++) {
           v = RARRAY_AREF(ary, i);
           if (result == Qundef || rb_cmpint(rb_yield_values(2, v, result), v, result) > 0) {
               result = v;
           }
        }
    }
    else {
        for (i = 0; i < RARRAY_LEN(ary); i++) {
           v = RARRAY_AREF(ary, i);
           if (result == Qundef || OPTIMIZED_CMP(v, result, cmp_opt) > 0) {
               result = v;
           }
        }
    }
    if (result == Qundef) return Qnil;
    return result;
}

Возвращает объект в ary с максимальным значением. Первая форма предполагает, что все объекты реализуют Comparable; вторая использует блок для возвращения a <=> b.

a = %w(albatross dog horse)
a.max                                   #=> "horse"
a.max { |a, b| a.length <=> b.length }  #=> "albatross"

Если задан аргумент n, возвращается массив из максимальных n элементов.

a = %w[albatross dog horse]
a.max(2)                                  #=> ["horse", "dog"]
a.max(2) {|a, b| a.length <=> b.length }  #=> ["albatross", "horse"]
min → obj Показать исходный код
min {| a,b | блок } → obj
min(n) → массив
min(n) {| a,b | блок } → массив
static VALUE
rb_ary_min(int argc, VALUE *argv, VALUE ary)
{
    struct cmp_opt_data cmp_opt = { 0, 0 };
    VALUE result = Qundef, v;
    VALUE num;
    long i;

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

    if (!NIL_P(num))
       return rb_nmin_run(ary, num, 0, 0, 1);

    if (rb_block_given_p()) {
        for (i = 0; i < RARRAY_LEN(ary); i++) {
           v = RARRAY_AREF(ary, i);
           if (result == Qundef || rb_cmpint(rb_yield_values(2, v, result), v, result) < 0) {
               result = v;
           }
        }
    }
    else {
        for (i = 0; i < RARRAY_LEN(ary); i++) {
           v = RARRAY_AREF(ary, i);
           if (result == Qundef || OPTIMIZED_CMP(v, result, cmp_opt) < 0) {
               result = v;
           }
        }
    }
    if (result == Qundef) return Qnil;
    return result;
}

Возвращает объект в ary с минимальным значением. Первая форма предполагает, что все объекты реализуют Comparable; вторая использует блок для возвращения a <=> b.

a = %w(albatross dog horse)
a.min                                   #=> "albatross"
a.min { |a, b| a.length <=> b.length }  #=> "dog"

Если задан аргумент n, возвращается массив из минимальных n элементов.

a = %w[albatross dog horse]
a.min(2)                                  #=> ["albatross", "dog"]
a.min(2) {|a, b| a.length <=> b.length }  #=> ["dog", "horse"]
pack( aTemplateString ) → aBinaryString Показать исходный код
pack( aTemplateString, buffer: aBufferString ) → aBufferString
static VALUE
pack_pack(int argc, VALUE *argv, VALUE ary)
{
    static const char nul10[] = "\0\0\0\0\0\0\0\0\0\0";
    static const char spc10[] = "          ";
    const char *p, *pend;
    VALUE fmt, opt = Qnil, res, from, associates = 0, buffer = 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;

    rb_scan_args(argc, argv, "10:", &fmt, &opt);

    StringValue(fmt);
    p = RSTRING_PTR(fmt);
    pend = p + RSTRING_LEN(fmt);
    if (!NIL_P(opt)) {
        static ID keyword_ids[1];
        if (!keyword_ids[0])
            CONST_ID(keyword_ids[0], "buffer");

        rb_get_kwargs(opt, keyword_ids, 0, 1, &buffer);

        if (buffer != Qundef && !RB_TYPE_P(buffer, T_STRING))
            rb_raise(rb_eTypeError, "buffer must be String, not %s", rb_obj_classname(buffer));
    }
    if (buffer)
        res = buffer;
    else
        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'' может быть последовой нижнего подчёркивания (“_'') или восклицательного знака (“!'') для использования собственного размера платформы для указанного типа; в противном случае используется независимый от платформы размер. Пробелы игнорируются в строке шаблона. См. также String#unpack.

a = [ "a", "b", "c" ]
n = [ 65, 66, 67 ]
a.pack("A3A3A3")   #=> "a  b  c  "
a.pack("a3a3a3")   #=> "a\000\000b\000\000c\000\000"
n.pack("ccc")      #=> "ABC"

Если задан aBufferString и его ёмкости достаточно, pack использует его как буфер и возвращает его. Когда смещение задаётся началом aTemplateString, результат заполняется после смещения. Если исходное содержимое aBufferString существует и оно длиннее смещения, остальная часть offsetOfBuffer перезаписывается результатом. Если оно короче, зазор заполняется “\0''.

Обратите внимание, что опция “buffer:'' не гарантирует, что память не будет выделена в pack. Если ёмкости aBufferString недостаточно, pack выделяет память.

Директивы для pack.

Integer       | Array   |
Directive     | Element | Meaning
----------------------------------------------------------------------------
C             | Integer | 8-bit unsigned (unsigned char)
S             | Integer | 16-bit unsigned, native endian (uint16_t)
L             | Integer | 32-bit unsigned, native endian (uint32_t)
Q             | Integer | 64-bit unsigned, native endian (uint64_t)
J             | Integer | pointer width unsigned, native endian (uintptr_t)
              |         | (J is available since Ruby 2.3.)
              |         |
c             | Integer | 8-bit signed (signed char)
s             | Integer | 16-bit signed, native endian (int16_t)
l             | Integer | 32-bit signed, native endian (int32_t)
q             | Integer | 64-bit signed, native endian (int64_t)
j             | Integer | pointer width signed, native endian (intptr_t)
              |         | (j is available since Ruby 2.3.)
              |         |
S_ S!         | Integer | unsigned short, native endian
I I_ I!       | Integer | unsigned int, native endian
L_ L!         | Integer | unsigned long, native endian
Q_ Q!         | Integer | unsigned long long, native endian (ArgumentError
              |         | if the platform has no long long type.)
              |         | (Q_ and Q! is available since Ruby 2.1.)
J!            | Integer | uintptr_t, native endian (same with J)
              |         | (J! is available since Ruby 2.3.)
              |         |
s_ s!         | Integer | signed short, native endian
i i_ i!       | Integer | signed int, native endian
l_ l!         | Integer | signed long, native endian
q_ q!         | Integer | signed long long, native endian (ArgumentError
              |         | if the platform has no long long type.)
              |         | (q_ and q! is available since Ruby 2.1.)
j!            | Integer | intptr_t, native endian (same with j)
              |         | (j! is available since Ruby 2.3.)
              |         |
S> s> S!> s!> | Integer | same as the directives without ">" except
L> l> L!> l!> |         | big endian
I!> i!>       |         | (available since Ruby 1.9.3)
Q> q> Q!> q!> |         | "S>" is same as "n"
J> j> J!> j!> |         | "L>" is same as "N"
              |         |
S< s< S!< s!< | Integer | same as the directives without "<" except
L< l< L!< l!< |         | little endian
I!< i!<       |         | (available since Ruby 1.9.3)
Q< q< Q!< q!< |         | "S<" is same as "v"
J< j< J!< j!< |         | "L<" is same as "V"
              |         |
n             | Integer | 16-bit unsigned, network (big-endian) byte order
N             | Integer | 32-bit unsigned, network (big-endian) byte order
v             | Integer | 16-bit unsigned, VAX (little-endian) byte order
V             | Integer | 32-bit unsigned, VAX (little-endian) byte order
              |         |
U             | Integer | UTF-8 character
w             | Integer | BER-compressed integer

Float        | Array   |
Directive    | Element | Meaning
---------------------------------------------------------------------------
D d          | Float   | double-precision, native format
F f          | Float   | single-precision, native format
E            | Float   | double-precision, little-endian byte order
e            | Float   | single-precision, little-endian byte order
G            | Float   | double-precision, network (big-endian) byte order
g            | Float   | single-precision, network (big-endian) byte order

String       | Array   |
Directive    | Element | Meaning
---------------------------------------------------------------------------
A            | String  | arbitrary binary string (space padded, count is width)
a            | String  | arbitrary binary string (null padded, count is width)
Z            | String  | same as ``a'', except that null is added with *
B            | String  | bit string (MSB first)
b            | String  | bit string (LSB first)
H            | String  | hex string (high nibble first)
h            | String  | hex string (low nibble first)
u            | String  | UU-encoded string
M            | String  | quoted printable, MIME encoding (see 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.        | Array   |
Directive    | Element | Meaning
---------------------------------------------------------------------------
@            | ---     | moves to absolute position
X            | ---     | back up a byte
x            | ---     | null byte
permutation { |p| block } → ary Show source
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 Show source
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 Show source
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([])          #=> []
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 Показать исходный код
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 Показать исходный код
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 Показать исходный код
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 возвращает значение true.

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

[1,2,3,4,5].select { |num|  num.even?  }   #=> [2, 4]

a = %w{ a b c d e f }
a.select { |v| v =~ /[aeiou]/ }  #=> ["a", "e"]

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

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 227
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, 0, 0);
        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.

Результат не гарантируется как стабильный. Когда сравнение двух элементов возвращает 0, порядок элементов непредсказуем.

a = [ "d", "a", "e", "c", "b" ]
a.sort                    #=> ["a", "b", "c", "d", "e"]
a.sort { |x,y| y <=> x }  #=> ["e", "d", "c", "b", "a"]

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

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.cmp_opt.opt_methods = 0;
        data.cmp_opt.opt_inited = 0;
        RARRAY_PTR_USE(tmp, ptr, {
            ruby_qsort(ptr, len, sizeof(VALUE),
                       rb_block_given_p()?sort_1:sort_2, &data);
        }); /* WB: no new reference */
        rb_ary_modify(ary);
        if (ARY_EMBED_P(tmp)) {
            if (ARY_SHARED_P(ary)) { /* ary might be destructively operated in the given block */
                rb_ary_unshare(ary);
                FL_SET_EMBED(ary);
            }
            ary_memcpy(ary, 0, ARY_EMBED_LEN(tmp), ARY_EMBED_PTR(tmp));
            ARY_SET_LEN(ary, ARY_EMBED_LEN(tmp));
        }
        else {
            if (!ARY_EMBED_P(ary) && ARY_HEAP_PTR(ary) == ARY_HEAP_PTR(tmp)) {
                FL_UNSET_SHARED(ary);
                ARY_SET_CAPA(ary, RARRAY_LEN(tmp));
            }
            else {
                assert(!ARY_SHARED_P(tmp));
                if (ARY_EMBED_P(ary)) {
                    FL_UNSET_EMBED(ary);
                }
                else if (ARY_SHARED_P(ary)) {
                    /* ary might be destructively operated in the given block */
                    rb_ary_unshare(ary);
                }
                else {
                    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.

Результат не гарантируется как стабильный. Когда сравнение двух элементов возвращает 0, порядок элементов непредсказуем.

a = [ "d", "a", "e", "c", "b" ]
a.sort!                    #=> ["a", "b", "c", "d", "e"]
a.sort! { |x,y| y <=> x }  #=> ["e", "d", "c", "b", "a"]

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

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.

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

sum(init=0) → number Показать исходный код
sum(init=0) {|e| expr } → number
static VALUE
rb_ary_sum(int argc, VALUE *argv, VALUE ary)
{
    VALUE e, v, r;
    long i, n;
    int block_given;

    if (rb_scan_args(argc, argv, "01", &v) == 0)
        v = LONG2FIX(0);

    block_given = rb_block_given_p();

    if (RARRAY_LEN(ary) == 0)
        return v;

    n = 0;
    r = Qundef;
    for (i = 0; i < RARRAY_LEN(ary); i++) {
        e = RARRAY_AREF(ary, i);
        if (block_given)
            e = rb_yield(e);
        if (FIXNUM_P(e)) {
            n += FIX2LONG(e); /* should not overflow long type */
            if (!FIXABLE(n)) {
                v = rb_big_plus(LONG2NUM(n), v);
                n = 0;
            }
        }
        else if (RB_TYPE_P(e, T_BIGNUM))
            v = rb_big_plus(e, v);
        else if (RB_TYPE_P(e, T_RATIONAL)) {
            if (r == Qundef)
                r = e;
            else
                r = rb_rational_plus(r, e);
        }
        else
            goto not_exact;
    }
    v = finish_exact_sum(n, r, v, argc!=0);
    return v;

  not_exact:
    v = finish_exact_sum(n, r, v, i!=0);

    if (RB_FLOAT_TYPE_P(e)) {
        /*
         * Kahan-Babuska balancing compensated summation algorithm
         * See http://link.springer.com/article/10.1007/s00607-005-0139-x
         */
        double f, c;

        f = NUM2DBL(v);
        c = 0.0;
        goto has_float_value;
        for (; i < RARRAY_LEN(ary); i++) {
            double x, t;
            e = RARRAY_AREF(ary, i);
            if (block_given)
                e = rb_yield(e);
            if (RB_FLOAT_TYPE_P(e))
              has_float_value:
                x = RFLOAT_VALUE(e);
            else if (FIXNUM_P(e))
                x = FIX2LONG(e);
            else if (RB_TYPE_P(e, T_BIGNUM))
                x = rb_big2dbl(e);
            else if (RB_TYPE_P(e, T_RATIONAL))
                x = rb_num2dbl(e);
            else
                goto not_float;

            if (isnan(f)) continue;
            if (isnan(x)) {
                f = x;
                continue;
            }
            if (isinf(x)) {
                if (isinf(f) && signbit(x) != signbit(f))
                    f = NAN;
                else
                    f = x;
                continue;
            }
            if (isinf(f)) continue;

            t = f + x;
            if (fabs(f) >= fabs(x))
                c += ((f - t) + x);
            else
                c += ((x - t) + f);
            f = t;
        }
        f += c;
        return DBL2NUM(f);

      not_float:
        v = DBL2NUM(f);
    }

    goto has_some_value;
    for (; i < RARRAY_LEN(ary); i++) {
        e = RARRAY_AREF(ary, i);
        if (block_given)
            e = rb_yield(e);
      has_some_value:
        v = rb_funcall(v, idPLUS, 1, e);
    }
    return v;
}

Возвращает сумму элементов. Например, [e1, e2, e3].sum возвращает init + e1 + e2 + e3.

Если задан блок, блок применяется к каждому элементу перед сложением.

Если ary пусто, возвращается init.

[].sum                             #=> 0
[].sum(0.0)                        #=> 0.0
[1, 2, 3].sum                      #=> 6
[3, 5.5].sum                       #=> 8.5
[2.5, 3.0].sum(0.0) {|e| e * e }   #=> 15.25
[Object.new].sum                   #=> TypeError

Среднее (арифметическое) значение массива можно получить следующим образом.

mean = ary.sum(0.0) / ary.length

Этот метод может использоваться для нечисленных объектов путём явного аргумента init.

["a", "b", "c"].sum("")            #=> "abc"
[[1], [[2]], [3]].sum([])          #=> [1, [2], 3]

Однако, #join и #flatten быстрее, чем #sum для массивов строк и массивов массивов.

["a", "b", "c"].join               #=> "abc"
[[1], [[2]], [3]].flatten(1)       #=> [1, [2], 3]

Метод #sum может не учитывать переопределение методов “+”, таких как Integer#+.

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}
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" ]
[ "c", "d", "a" ] | [ "a", "b", "c" ]    #=> [ "c", "d", "a", "b" ]

См. также #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