类 Array
数组是一个有序的、整数索引的、称为元素的对象集合。任何对象(甚至是另一个数组)都可以是数组元素,数组可以包含不同类型的对象。
数组索引¶ ↑
数组索引从 0 开始,就像 C 或 Java 一样。
正索引是从第一个元素开始的偏移量
-
索引 0 表示第一个元素。
-
索引 1 表示第二个元素。
-
…
负索引是从数组末尾开始的偏移量
-
索引 -1 表示最后一个元素。
-
索引 -2 表示倒数第二个元素。
-
…
非负索引在范围内当且仅当它小于数组的大小。对于一个 3 元素数组
-
索引 0 到 2 在范围内。
-
索引 3 超出范围。
负索引在范围内当且仅当它的绝对值不大于数组的大小。对于一个 3 元素数组
-
索引 -1 到 -3 在范围内。
-
索引 -4 超出范围。
虽然数组中的有效索引始终是整数,但某些方法(在类 Array 内部和外部)都接受一个或多个非整数参数,这些参数是 可转换为整数的对象。
创建数组¶ ↑
您可以使用以下方法显式创建 Array 对象
-
数组字面量
[1, 'one', :one, [2, 'two', :two]]
-
数组字面量
%w[foo bar baz] # => ["foo", "bar", "baz"] %w[1 % *] # => ["1", "%", "*"]
-
数组字面量
%i[foo bar baz] # => [:foo, :bar, :baz] %i[1 % *] # => [:"1", :%, :*]
-
方法
Kernel#Array
Array(["a", "b"]) # => ["a", "b"] Array(1..5) # => [1, 2, 3, 4, 5] Array(key: :value) # => [[:key, :value]] Array(nil) # => [] Array(1) # => [1] Array({:a => "a", :b => "b"}) # => [[:a, "a"], [:b, "b"]]
-
方法
Array.new
Array.new # => [] Array.new(3) # => [nil, nil, nil] Array.new(4) {Hash.new} # => [{}, {}, {}, {}] Array.new(3, true) # => [true, true, true]
请注意,上面的最后一个示例使用对同一个对象的引用来填充数组。这仅在该对象是本机不可变对象(如符号、数字、
nil
、true
或false
)时才推荐。另一种使用块创建包含各种对象的数组的方法;这种用法对于可变对象(如哈希、字符串或其他数组)是安全的
Array.new(4) {|i| i.to_s } # => ["0", "1", "2", "3"]
以下是如何创建多维数组的方法
Array.new(3) {Array.new(3)} # => [[nil, nil, nil], [nil, nil, nil], [nil, nil, nil]]
许多 Ruby 方法(在核心和标准库中)都提供实例方法 to_a
,该方法将对象转换为数组。
-
OptionParser#to_a
-
Set#to_a
-
Benchmark::Tms#to_a
-
CSV::Table#to_a
-
Gem::List#to_a
-
Gem::NameTuple#to_a
-
Gem::Platform#to_a
-
Gem::RequestSet::Lockfile::Tokenizer#to_a
-
Gem::SourceList#to_a
-
OpenSSL::X509::Extension#to_a
-
OpenSSL::X509::Name#to_a
-
Racc::ISet#to_a
-
Rinda::RingFinger#to_a
-
Ripper::Lexer::Elem#to_a
-
YAML::DBM#to_a
示例用法¶ ↑
除了通过 Enumerable
模块混合进来的方法之外,Array 类还拥有用于访问、搜索和操作数组的专有方法。
下面将说明一些比较常用的方法。
访问元素¶ ↑
可以使用 Array#[]
方法检索数组中的元素。它可以接受一个整数参数(数字索引)、一对参数(起始位置和长度)或一个范围。负索引从末尾开始计数,-1 代表最后一个元素。
arr = [1, 2, 3, 4, 5, 6] arr[2] #=> 3 arr[100] #=> nil arr[-3] #=> 4 arr[2, 3] #=> [3, 4, 5] arr[1..4] #=> [2, 3, 4, 5] arr[1..-3] #=> [2, 3, 4]
另一种访问特定数组元素的方法是使用 at
方法
arr.at(0) #=> 1
要对超出数组边界的索引引发错误,或者在发生这种情况时提供默认值,可以使用 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
向数组添加项目¶ ↑
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']
另一个常见需求是从数组中删除重复元素。
arr = [2, 5, 6, 556, 6, 6, 8, 9, 0, 123, 556] arr.uniq #=> [2, 5, 6, 556, 8, 9, 0, 123]
遍历数组¶ ↑
与包含 Enumerable
模块的所有类一样,Array 也有一个 each 方法,它定义了应该遍历哪些元素以及如何遍历。在 Array 的 each
情况下,Array 实例中的所有元素都将按顺序传递给提供的块。
请注意,此操作不会更改数组。
arr = [1, 2, 3, 4, 5] arr.each {|a| print a -= 10, " "} # prints: -9 -8 -7 -6 -5 #=> [1, 2, 3, 4, 5]
另一个有时有用的迭代器是 reverse_each
,它将以相反的顺序遍历数组中的元素。
words = %w[first second third fourth fifth sixth] str = "" words.reverse_each {|word| str += "#{word} "} p str #=> "sixth fifth fourth third second first "
可以使用 map
方法根据原始数组创建一个新数组,但值将由提供的块修改。
arr.map {|a| 2*a} #=> [2, 4, 6, 8, 10] arr #=> [1, 2, 3, 4, 5] arr.map! {|a| a**2} #=> [1, 4, 9, 16, 25] arr #=> [1, 4, 9, 16, 25]
从数组中选择项目¶ ↑
可以根据块中定义的条件从数组中选择元素。选择可以以破坏性或非破坏性的方式进行。虽然破坏性操作会修改它们调用的数组,但非破坏性方法通常会返回一个包含所选元素的新数组,但不会改变原始数组。
非破坏性选择¶ ↑
arr = [1, 2, 3, 4, 5, 6] arr.select {|a| a > 3} #=> [4, 5, 6] arr.reject {|a| a < 3} #=> [3, 4, 5, 6] arr.drop_while {|a| a < 4} #=> [4, 5, 6] arr #=> [1, 2, 3, 4, 5, 6]
破坏性选择¶ ↑
select!
和 reject!
是 select
和 reject
的对应破坏性方法。
类似于 select
与 reject
,delete_if
和 keep_if
在提供相同块时具有完全相反的结果。
arr.delete_if {|a| a < 4} #=> [4, 5, 6] arr #=> [4, 5, 6] arr = [1, 2, 3, 4, 5, 6] arr.keep_if {|a| a < 4} #=> [1, 2, 3] arr #=> [1, 2, 3]
这里有什么¶ ↑
首先,其他地方有什么。类数组
-
继承自 类对象。
-
包含 模块 Enumerable,它提供了数十种附加方法。
这里,类数组提供了对以下内容有用的方法:
创建数组的方法¶ ↑
-
::[]
:返回一个用给定对象填充的新数组。 -
::new
:返回一个新数组。 -
::try_convert
:返回一个由给定对象创建的新数组。
查询方法¶ ↑
-
include?
:返回任何元素是否==
给定对象。 -
empty?
: 返回数组是否为空。 -
all?
: 返回数组中所有元素是否满足给定条件。 -
any?
: 返回数组中是否存在满足给定条件的元素。 -
none?
: 返回数组中是否没有元素与给定对象相等。 -
one?
: 返回数组中是否只有一个元素与给定对象相等。 -
count
: 返回满足给定条件的元素数量。 -
find_index
,index
: 返回第一个满足给定条件的元素的索引。 -
rindex
: 返回最后一个满足给定条件的元素的索引。 -
hash
: 返回数组的整数哈希值。
比较方法¶ ↑
-
#<=>: 返回 -1、0 或 1,分别表示
self
小于、等于或大于给定对象。 -
==
: 返回self
中的每个元素是否与给定对象中的对应元素相等。 -
eql?
: 返回self
中的每个元素是否与给定对象中的对应元素相等。
获取方法¶ ↑
这些方法不会修改 self
。
-
[]
: 返回一个或多个元素。 -
fetch
: 返回给定偏移处的元素。 -
first
: 返回一个或多个前导元素。 -
last
: 返回一个或多个尾随元素。 -
max
: 返回一个或多个最大值元素,由<=>
或给定块决定。 -
min
: 返回一个或多个最小值元素,由<=>
或给定块决定。 -
minmax
: 返回最小值元素和最大值元素,由<=>
或给定块决定。 -
assoc
: 返回第一个元素,该元素是一个数组,其第一个元素与给定对象相等。 -
rassoc
: 返回第一个元素,该元素是一个数组,其第二个元素与给定对象相等。 -
at
: 返回给定偏移处的元素。 -
values_at
: 返回给定偏移处的元素。 -
dig
: 返回嵌套对象中由给定索引和附加参数指定的元素。 -
drop
: 返回根据给定索引确定的尾部元素。 -
take
: 返回根据给定索引确定的头部元素。 -
drop_while
: 返回根据给定代码块确定的尾部元素。 -
take_while
: 返回根据给定代码块确定的头部元素。 -
slice
: 返回根据给定参数确定的连续元素。 -
sort
: 返回根据<=>
或给定代码块确定的顺序排列的所有元素。 -
reverse
: 返回所有元素的逆序排列。 -
compact
: 返回一个包含所有非nil
元素的数组。 -
uniq
: 返回一个包含非重复元素的数组。 -
rotate
: 返回所有元素,其中一些元素从一端旋转到另一端。 -
bsearch
: 返回通过二分搜索选择的元素,该元素由给定代码块确定。 -
bsearch_index
: 返回通过二分搜索选择的元素的索引,该元素由给定代码块确定。 -
sample
: 返回一个或多个随机元素。 -
shuffle
: 返回以随机顺序排列的元素。
分配方法¶ ↑
这些方法在self
中添加、替换或重新排序元素。
-
[]=
: 使用给定对象分配指定元素。 -
insert
: 在给定偏移量处插入给定对象;不替换元素。 -
concat
: 将给定数组中的所有元素追加到当前数组。 -
fill
: 用指定的对象替换指定元素。 -
replace
: 用给定数组的内容替换当前数组的内容。 -
reverse!
: 将当前数组替换为其元素反转后的数组。 -
rotate!
: 将当前数组替换为其元素旋转后的数组。 -
shuffle!
: 将当前数组替换为其元素随机排序后的数组。 -
sort!
: 将当前数组替换为其元素排序后的数组,排序方式由<=>
或给定的代码块决定。 -
sort_by!
: 将当前数组替换为其元素排序后的数组,排序方式由给定的代码块决定。
删除方法¶ ↑
这些方法都从当前数组中删除元素。
-
pop
: 删除并返回最后一个元素。 -
shift
: 删除并返回第一个元素。 -
compact!
: 删除所有nil
元素。 -
delete
: 删除与给定对象相等的元素。 -
delete_at
: 删除给定偏移处的元素。 -
delete_if
: 删除由给定代码块指定的元素。 -
keep_if
: 删除由给定代码块未指定的元素。 -
reject!
: 删除由给定代码块指定的元素。 -
slice!
: 删除并返回一系列元素。 -
uniq!
: 删除重复项。
组合方法¶ ↑
-
#&: 返回一个数组,其中包含当前数组和给定数组中都存在的元素。
-
intersection
: 返回一个数组,其中包含当前数组和每个给定数组中都存在的元素。 -
+
: 返回一个数组,其中包含当前数组的所有元素,后面跟着给定数组的所有元素。 -
-
: 返回一个数组,其中包含当前数组中所有不在给定数组中的元素。 -
#|: 返回一个数组,其中包含当前数组的所有元素和给定数组的所有元素,删除重复项。
-
union
: 返回一个数组,其中包含当前数组的所有元素和所有给定数组的所有元素,删除重复项。 -
difference
: 返回一个数组,其中包含当前数组中所有不在任何给定数组中的元素。 -
product
: 返回或生成来自self
和给定数组的所有元素组合。
迭代方法¶ ↑
-
each
: 将每个元素传递给给定的代码块。 -
reverse_each
: 将每个元素(以相反顺序)传递给给定的代码块。 -
each_index
: 将每个元素索引传递给给定的代码块。 -
cycle
: 使用每个元素调用给定的代码块,然后再次执行,持续指定的次数或永远执行。 -
combination
: 使用self
的元素组合调用给定的代码块;组合不会重复使用相同的元素。 -
permutation
: 使用self
的元素排列调用给定的代码块;排列不会重复使用相同的元素。 -
repeated_combination
: 使用self
的元素组合调用给定的代码块;组合可以重复使用相同的元素。 -
repeated_permutation
: 使用self
的元素排列调用给定的代码块;排列可以重复使用相同的元素。
转换方法¶ ↑
-
flatten
: 返回一个数组,它是self
的递归扁平化结果。 -
flatten!
: 用来自该数组的元素替换self
中的每个嵌套数组。 -
join
: 返回一个新的 String,其中包含由字段分隔符连接的元素。 -
to_a
: 返回self
或包含所有元素的新数组。 -
to_ary
: 返回self
。 -
to_h
: 返回由元素形成的新哈希。 -
transpose
: 转置self
,它必须是数组的数组。 -
zip
: 返回包含self
和给定数组的新数组;有关详细信息,请参阅链接。
其他方法¶ ↑
公共类方法
返回一个用给定对象填充的新数组。
Array.[]( 1, 'a', /^A/) # => [1, "a", /^A/] Array[ 1, 'a', /^A/ ] # => [1, "a", /^A/] [ 1, 'a', /^A/ ] # => [1, "a", /^A/]
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。
没有代码块和参数,返回一个新的空 Array 对象。
没有代码块和单个 Array 参数 array
,返回一个由 array
形成的新 Array。
a = Array.new([:foo, 'bar', 2]) a.class # => Array a # => [:foo, "bar", 2]
没有代码块和单个 Integer
参数 size
,返回一个给定大小的新 Array,其元素均为 nil
。
a = Array.new(3) a # => [nil, nil, nil]
没有代码块和参数 size
和 default_value
,返回一个给定大小的 Array;每个元素都是相同的 default_value
。
a = Array.new(3, 'x') a # => ['x', 'x', 'x']
带有代码块和参数 size
,返回一个给定大小的 Array;代码块使用每个连续的整数 index
调用;该 index
的元素是代码块的返回值。
a = Array.new(3) {|index| "Element #{index}" } a # => ["Element 0", "Element 1", "Element 2"]
如果 size
为负数,则引发 ArgumentError
。
带有代码块和没有参数,或单个参数 0
,忽略代码块并返回一个新的空 Array。
static VALUE rb_ary_initialize(int argc, VALUE *argv, VALUE ary) { long len; VALUE size, val; rb_ary_modify(ary); if (argc == 0) { rb_ary_reset(ary); assert(ARY_EMBED_P(ary)); assert(ARY_EMBED_LEN(ary) == 0); if (rb_block_given_p()) { rb_warning("given block not used"); } return ary; } rb_scan_args(argc, argv, "02", &size, &val); if (argc == 1 && !FIXNUM_P(size)) { val = rb_check_array_type(size); if (!NIL_P(val)) { rb_ary_replace(ary, val); return ary; } } len = NUM2LONG(size); /* NUM2LONG() may call size.to_int, ary can be frozen, modified, etc */ if (len < 0) { rb_raise(rb_eArgError, "negative array size"); } if (len > ARY_MAX_SIZE) { rb_raise(rb_eArgError, "array size too big"); } /* recheck after argument conversion */ rb_ary_modify(ary); ary_resize_capa(ary, len); if (rb_block_given_p()) { long i; if (argc == 2) { rb_warn("block supersedes default value argument"); } for (i=0; i<len; i++) { rb_ary_store(ary, i, rb_yield(LONG2NUM(i))); ARY_SET_LEN(ary, i + 1); } } else { ary_memfill(ary, 0, len, val); ARY_SET_LEN(ary, len); } return ary; }
如果 object
是一个 Array 对象,则返回 object
。
否则,如果 object
响应 :to_ary
,则调用 object.to_ary
并返回结果。
如果 object
不响应 :to_ary
,则返回 nil
。
除非 object.to_ary
返回一个 Array 对象,否则会抛出异常。
static VALUE rb_ary_s_try_convert(VALUE dummy, VALUE ary) { return rb_check_array_type(ary); }
公共实例方法
返回一个新的 Array,其中包含 array
和 Array other_array
中找到的每个元素;重复项被省略;使用 eql?
比较项目(项目还必须正确实现 hash
)。
[0, 1, 2, 3] & [1, 2] # => [1, 2] [0, 1, 0, 1] & [0, 1] # => [0, 1]
保留来自 array
的顺序。
[0, 1, 2] & [3, 2, 1, 0] # => [0, 1, 2]
static VALUE rb_ary_and(VALUE ary1, VALUE ary2) { VALUE hash, ary3, v; st_data_t vv; long i; ary2 = to_ary(ary2); ary3 = rb_ary_new(); if (RARRAY_LEN(ary1) == 0 || RARRAY_LEN(ary2) == 0) return ary3; if (RARRAY_LEN(ary1) <= SMALL_ARRAY_LEN && RARRAY_LEN(ary2) <= SMALL_ARRAY_LEN) { for (i=0; i<RARRAY_LEN(ary1); i++) { v = RARRAY_AREF(ary1, i); if (!rb_ary_includes_by_eql(ary2, v)) continue; if (rb_ary_includes_by_eql(ary3, v)) continue; rb_ary_push(ary3, v); } return ary3; } hash = ary_make_hash(ary2); for (i=0; i<RARRAY_LEN(ary1); i++) { v = RARRAY_AREF(ary1, i); vv = (st_data_t)v; if (rb_hash_stlike_delete(hash, &vv, 0)) { rb_ary_push(ary3, v); } } return ary3; }
当给出非负参数 Integer
n
时,返回一个新的 Array,该 Array 通过连接 self
的 n
个副本构建。
a = ['x', 'y'] a * 3 # => ["x", "y", "x", "y", "x", "y"]
当给出 String
参数 string_separator
时,等效于 array.join(string_separator)
。
[0, [0, 1], {foo: 0}] * ', ' # => "0, 0, 1, {:foo=>0}"
static VALUE rb_ary_times(VALUE ary, VALUE times) { VALUE ary2, tmp; const VALUE *ptr; long t, len; tmp = rb_check_string_type(times); if (!NIL_P(tmp)) { return rb_ary_join(ary, tmp); } len = NUM2LONG(times); if (len == 0) { ary2 = ary_new(rb_cArray, 0); goto out; } if (len < 0) { rb_raise(rb_eArgError, "negative argument"); } if (ARY_MAX_SIZE/len < RARRAY_LEN(ary)) { rb_raise(rb_eArgError, "argument too big"); } len *= RARRAY_LEN(ary); ary2 = ary_new(rb_cArray, len); ARY_SET_LEN(ary2, len); ptr = RARRAY_CONST_PTR(ary); t = RARRAY_LEN(ary); if (0 < t) { ary_memcpy(ary2, 0, t, ptr); while (t <= len/2) { ary_memcpy(ary2, t, t, RARRAY_CONST_PTR(ary2)); t *= 2; } if (t < len) { ary_memcpy(ary2, t, len-t, RARRAY_CONST_PTR(ary2)); } } out: return ary2; }
返回一个新的 Array,其中包含 array
的所有元素,后跟 other_array
的所有元素。
a = [0, 1] + [2, 3] a # => [0, 1, 2, 3]
相关:concat
.
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; }
返回一个新的 Array,其中仅包含 array
中未在 Array other_array
中找到的元素;使用 eql?
比较项目;保留来自 array
的顺序。
[0, 1, 1, 2, 1, 1, 3, 1, 1] - [1] # => [0, 2, 3] [0, 1, 2, 3] - [3, 0] # => [1, 2] [0, 1, 2] - [4] # => [0, 1, 2]
相关:Array#difference
.
VALUE rb_ary_diff(VALUE ary1, VALUE ary2) { VALUE ary3; VALUE hash; long i; ary2 = to_ary(ary2); if (RARRAY_LEN(ary2) == 0) { return ary_make_shared_copy(ary1); } ary3 = rb_ary_new(); if (RARRAY_LEN(ary1) <= SMALL_ARRAY_LEN || RARRAY_LEN(ary2) <= SMALL_ARRAY_LEN) { for (i=0; i<RARRAY_LEN(ary1); i++) { VALUE elt = rb_ary_elt(ary1, i); if (rb_ary_includes_by_eql(ary2, elt)) continue; rb_ary_push(ary3, elt); } return ary3; } hash = ary_make_hash(ary2); for (i=0; i<RARRAY_LEN(ary1); i++) { if (rb_hash_stlike_lookup(hash, RARRAY_AREF(ary1, i), NULL)) continue; rb_ary_push(ary3, rb_ary_elt(ary1, i)); } return ary3; }
将 object
附加到 self
;返回 self
。
a = [:foo, 'bar', 2] a << :baz # => [:foo, "bar", 2, :baz]
将 object
附加为一个元素,即使它是另一个 Array。
a = [:foo, 'bar', 2] a1 = a << [3, 4] a1 # => [:foo, "bar", 2, [3, 4]]
VALUE rb_ary_push(VALUE ary, VALUE item) { long idx = RARRAY_LEN((ary_verify(ary), ary)); VALUE target_ary = ary_ensure_room_for_push(ary, 1); RARRAY_PTR_USE(ary, ptr, { RB_OBJ_WRITE(target_ary, &ptr[idx], item); }); ARY_SET_LEN(ary, idx + 1); ary_verify(ary); return ary; }
返回 -1、0 或 1,表示 self
小于、等于或大于 other_array
。对于 self
中的每个索引 i
,计算 result = self[i] <=> other_array[i]
。
如果任何结果为 -1,则返回 -1
[0, 1, 2] <=> [0, 1, 3] # => -1
如果任何结果为 1,则返回 1
[0, 1, 2] <=> [0, 1, 1] # => 1
当所有结果都为零时
-
如果
array
小于other_array
,则返回 -1[0, 1, 2] <=> [0, 1, 2, 3] # => -1
-
如果
array
大于other_array
,则返回 1[0, 1, 2] <=> [0, 1] # => 1
-
如果
array
和other_array
大小相同,则返回 0[0, 1, 2] <=> [0, 1, 2] # => 0
VALUE rb_ary_cmp(VALUE ary1, VALUE ary2) { long len; VALUE v; ary2 = rb_check_array_type(ary2); if (NIL_P(ary2)) return Qnil; if (ary1 == ary2) return INT2FIX(0); v = rb_exec_recursive_paired(recursive_cmp, ary1, ary2, ary2); if (!UNDEF_P(v)) return v; len = RARRAY_LEN(ary1) - RARRAY_LEN(ary2); if (len == 0) return INT2FIX(0); if (len > 0) return INT2FIX(1); return INT2FIX(-1); }
如果 array.size == other_array.size
并且对于 array
中的每个索引 i
,array[i] == other_array[i]
,则返回 true
a0 = [:foo, 'bar', 2] a1 = [:foo, 'bar', 2.0] a1 == a0 # => true [] == [] # => true
否则,返回 false
。
此方法与方法 Array#eql?
不同,后者使用 Object#eql?
比较元素。
static VALUE rb_ary_equal(VALUE ary1, VALUE ary2) { if (ary1 == ary2) return Qtrue; if (!RB_TYPE_P(ary2, T_ARRAY)) { if (!rb_respond_to(ary2, idTo_ary)) { return Qfalse; } return rb_equal(ary2, ary1); } if (RARRAY_LEN(ary1) != RARRAY_LEN(ary2)) return Qfalse; if (RARRAY_CONST_PTR(ary1) == RARRAY_CONST_PTR(ary2)) return Qtrue; return rb_exec_recursive_paired(recursive_equal, ary1, ary2, ary2); }
返回 self
中的元素;不修改 self
。
当给定单个 Integer
参数 index
时,返回偏移量为 index
的元素
a = [:foo, 'bar', 2] a[0] # => :foo a[2] # => 2 a # => [:foo, "bar", 2]
如果 index
为负数,则相对于 self
的末尾进行计数
a = [:foo, 'bar', 2] a[-1] # => 2 a[-2] # => "bar"
如果 index
超出范围,则返回 nil
。
当给定两个 Integer
参数 start
和 length
时,返回一个新的大小为 length
的数组,其中包含从偏移量 start
开始的连续元素
a = [:foo, 'bar', 2] a[0, 2] # => [:foo, "bar"] a[1, 2] # => ["bar", 2]
如果 start + length
大于 self.length
,则返回从偏移量 start
到末尾的所有元素
a = [:foo, 'bar', 2] a[0, 4] # => [:foo, "bar", 2] a[1, 3] # => ["bar", 2] a[2, 2] # => [2]
如果 start == self.size
且 length >= 0
,则返回一个新的空数组。
如果 length
为负数,则返回 nil
。
当给定单个 Range
参数 range
时,将 range.min
视为上面的 start
,将 range.size
视为上面的 length
a = [:foo, 'bar', 2] a[0..1] # => [:foo, "bar"] a[1..2] # => ["bar", 2]
特殊情况:如果 range.start == a.size
,则返回一个新的空数组。
如果 range.end
为负数,则从末尾计算结束索引
a = [:foo, 'bar', 2] a[0..-1] # => [:foo, "bar", 2] a[0..-2] # => [:foo, "bar"] a[0..-3] # => [:foo]
如果 range.start
为负数,则从末尾计算开始索引
a = [:foo, 'bar', 2] a[-1..2] # => [2] a[-2..2] # => ["bar", 2] a[-3..2] # => [:foo, "bar", 2]
如果 range.start
大于数组大小,则返回 nil
。
a = [:foo, 'bar', 2] a[4..1] # => nil a[4..0] # => nil a[4..-1] # => nil
当给定单个 Enumerator::ArithmeticSequence
参数 aseq
时,返回一个数组,其中包含与序列生成的索引相对应的元素。
a = ['--', 'data1', '--', 'data2', '--', 'data3'] a[(1..).step(2)] # => ["data1", "data2", "data3"]
与使用范围切片不同,如果算术序列的开始或结束大于数组大小,则会抛出 RangeError
。
a = ['--', 'data1', '--', 'data2', '--', 'data3'] a[(1..11).step(2)] # RangeError (((1..11).step(2)) out of range) a[(7..).step(2)] # RangeError (((7..).step(2)) out of range)
如果给定单个参数,并且其类型不是列出的类型之一,则尝试将其转换为 Integer
,如果无法转换,则会引发异常。
a = [:foo, 'bar', 2] # Raises TypeError (no implicit conversion of Symbol into Integer): a[:foo]
VALUE rb_ary_aref(int argc, const VALUE *argv, VALUE ary) { rb_check_arity(argc, 1, 2); if (argc == 2) { return rb_ary_aref2(ary, argv[0], argv[1]); } return rb_ary_aref1(ary, argv[0]); }
为 self
中的元素赋值;返回给定的 object
。
当给定 Integer
参数 index
时,将 object
赋值给 self
中的元素。
如果 index
非负,则将 object
赋值给偏移量为 index
的元素。
a = [:foo, 'bar', 2] a[0] = 'foo' # => "foo" a # => ["foo", "bar", 2]
如果 index
大于 self.length
,则扩展数组。
a = [:foo, 'bar', 2] a[7] = 'foo' # => "foo" a # => [:foo, "bar", 2, nil, nil, nil, nil, "foo"]
如果 index
为负数,则从数组末尾反向计数。
a = [:foo, 'bar', 2] a[-1] = 'two' # => "two" a # => [:foo, "bar", "two"]
当给定 Integer
参数 start
和 length
且 object
不是数组时,从偏移量 start
开始删除 length - 1
个元素,并将 object
赋值给偏移量 start
的元素。
a = [:foo, 'bar', 2] a[0, 2] = 'foo' # => "foo" a # => ["foo", 2]
如果 start
为负数,则从数组末尾反向计数。
a = [:foo, 'bar', 2] a[-2, 2] = 'foo' # => "foo" a # => [:foo, "foo"]
如果 start
非负且超出数组范围 ( >= self.size
),则使用 nil
扩展数组,将 object
赋值给偏移量 start
的元素,并忽略 length
。
a = [:foo, 'bar', 2] a[6, 50] = 'foo' # => "foo" a # => [:foo, "bar", 2, nil, nil, nil, "foo"]
如果 length
为零,则将偏移量 start
及其后的元素移位,并将 object
赋值给偏移量 start
的元素。
a = [:foo, 'bar', 2] a[1, 0] = 'foo' # => "foo" a # => [:foo, "foo", "bar", 2]
如果 length
超出现有数组的大小,则不会扩展数组。
a = [:foo, 'bar', 2] a[1, 5] = 'foo' # => "foo" a # => [:foo, "foo"]
当给定 Range
参数 range
且 object
是数组时,从偏移量 start
开始删除 length - 1
个元素,并将 object
赋值给偏移量 start
的元素。
a = [:foo, 'bar', 2] a[0..1] = 'foo' # => "foo" a # => ["foo", 2]
如果 range.begin
为负数,则从数组末尾反向计数。
a = [:foo, 'bar', 2] a[-2..2] = 'foo' # => "foo" a # => [:foo, "foo"]
如果数组长度小于 range.begin
,则将 object
赋值给偏移量 range.begin
的元素,并忽略 length
。
a = [:foo, 'bar', 2] a[6..50] = 'foo' # => "foo" a # => [:foo, "bar", 2, nil, nil, nil, "foo"]
如果 range.end
为零,则将偏移量 start
及其后的元素移位,并将 object
赋值给偏移量 start
的元素。
a = [:foo, 'bar', 2] a[1..0] = 'foo' # => "foo" a # => [:foo, "foo", "bar", 2]
如果 range.end
为负数,则将 object
赋值给偏移量 start
的元素,保留 range.end.abs -1
个元素,并删除超出范围的元素。
a = [:foo, 'bar', 2] a[1..-1] = 'foo' # => "foo" a # => [:foo, "foo"] a = [:foo, 'bar', 2] a[1..-2] = 'foo' # => "foo" a # => [:foo, "foo", 2] a = [:foo, 'bar', 2] a[1..-3] = 'foo' # => "foo" a # => [:foo, "foo", "bar", 2] a = [:foo, 'bar', 2]
如果 range.end
超出现有数组的大小,则替换数组元素,但不会使用 nil
值扩展数组。
a = [:foo, 'bar', 2] a[1..5] = 'foo' # => "foo" a # => [:foo, "foo"]
static VALUE rb_ary_aset(int argc, VALUE *argv, VALUE ary) { long offset, beg, len; rb_check_arity(argc, 2, 3); rb_ary_modify_check(ary); if (argc == 3) { beg = NUM2LONG(argv[0]); len = NUM2LONG(argv[1]); return ary_aset_by_rb_ary_splice(ary, beg, len, argv[2]); } if (FIXNUM_P(argv[0])) { offset = FIX2LONG(argv[0]); return ary_aset_by_rb_ary_store(ary, offset, argv[1]); } if (rb_range_beg_len(argv[0], &beg, &len, RARRAY_LEN(ary), 1)) { /* check if idx is Range */ return ary_aset_by_rb_ary_splice(ary, beg, len, argv[1]); } offset = NUM2LONG(argv[0]); return ary_aset_by_rb_ary_store(ary, offset, argv[1]); }
如果 self
中的所有元素都满足给定条件,则返回 true
。
如果 self
没有元素,则返回 true
,并且不使用参数或代码块。
如果没有给出代码块并且没有参数,如果 self
仅包含真值元素,则返回 true
,否则返回 false
[0, 1, :foo].all? # => true [0, nil, 2].all? # => false [].all? # => true
如果给出代码块但没有参数,则使用 self
中的每个元素调用代码块;如果代码块仅返回真值,则返回 true
,否则返回 false
[0, 1, 2].all? { |element| element < 3 } # => true [0, 1, 2].all? { |element| element < 2 } # => false
如果给出参数 obj
,如果 obj.===
每个元素,则返回 true
,否则返回 false
['food', 'fool', 'foot'].all?(/foo/) # => true ['food', 'drink'].all?(/bar/) # => false [].all?(/foo/) # => true [0, 0, 0].all?(0) # => true [0, 1, 2].all?(1) # => false
static VALUE rb_ary_all_p(int argc, VALUE *argv, VALUE ary) { long i, len = RARRAY_LEN(ary); rb_check_arity(argc, 0, 1); if (!len) return Qtrue; if (argc) { if (rb_block_given_p()) { rb_warn("given block not used"); } for (i = 0; i < RARRAY_LEN(ary); ++i) { if (!RTEST(rb_funcall(argv[0], idEqq, 1, RARRAY_AREF(ary, i)))) return Qfalse; } } else if (!rb_block_given_p()) { for (i = 0; i < len; ++i) { if (!RTEST(RARRAY_AREF(ary, i))) return Qfalse; } } else { for (i = 0; i < RARRAY_LEN(ary); ++i) { if (!RTEST(rb_yield(RARRAY_AREF(ary, i)))) return Qfalse; } } return Qtrue; }
如果 self
中的任何元素都满足给定条件,则返回 true
。
如果 self
没有元素,则返回 false
,并且不使用参数或代码块。
如果没有给出代码块并且没有参数,如果 self
包含任何真值元素,则返回 true
,否则返回 false
[nil, 0, false].any? # => true [nil, false].any? # => false [].any? # => false
如果给出代码块但没有参数,则使用 self
中的每个元素调用代码块;如果代码块返回任何真值,则返回 true
,否则返回 false
[0, 1, 2].any? {|element| element > 1 } # => true [0, 1, 2].any? {|element| element > 2 } # => false
如果给出参数 obj
,如果 obj
.===
任何元素,则返回 true
,否则返回 false
['food', 'drink'].any?(/foo/) # => true ['food', 'drink'].any?(/bar/) # => false [].any?(/foo/) # => false [0, 1, 2].any?(1) # => true [0, 1, 2].any?(3) # => false
static VALUE rb_ary_any_p(int argc, VALUE *argv, VALUE ary) { long i, len = RARRAY_LEN(ary); rb_check_arity(argc, 0, 1); if (!len) return Qfalse; if (argc) { if (rb_block_given_p()) { rb_warn("given block not used"); } for (i = 0; i < RARRAY_LEN(ary); ++i) { if (RTEST(rb_funcall(argv[0], idEqq, 1, RARRAY_AREF(ary, i)))) return Qtrue; } } else if (!rb_block_given_p()) { for (i = 0; i < len; ++i) { if (RTEST(RARRAY_AREF(ary, i))) return Qtrue; } } else { for (i = 0; i < RARRAY_LEN(ary); ++i) { if (RTEST(rb_yield(RARRAY_AREF(ary, i)))) return Qtrue; } } return Qfalse; }
追加尾部元素。
将 objects
中的每个参数追加到 self
中;返回 self
a = [:foo, 'bar', 2] a.push(:baz, :bat) # => [:foo, "bar", 2, :baz, :bat]
将每个参数追加为一个元素,即使它是另一个数组
a = [:foo, 'bar', 2] a1 = a.push([:baz, :bat], [:bam, :bad]) a1 # => [:foo, "bar", 2, [:baz, :bat], [:bam, :bad]]
返回self
中第一个元素,该元素是一个数组,其第一个元素==
obj
a = [{foo: 0}, [2, 4], [4, 5, 6], [4, 5]] a.assoc(4) # => [4, 5, 6]
如果找不到这样的元素,则返回nil
。
相关:rassoc
.
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; }
返回Integer
偏移量index
处的元素;不修改self
。
a = [:foo, 'bar', 2] a.at(0) # => :foo a.at(2) # => 2
VALUE rb_ary_at(VALUE ary, VALUE pos) { return rb_ary_entry(ary, NUM2LONG(pos)); }
返回self
中通过二分查找选择的元素。
参见二分查找.
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; }
按方法bsearch
中描述的方式搜索self
,但返回找到元素的索引,而不是元素本身。
static VALUE rb_ary_bsearch_index(VALUE ary) { long low = 0, high = RARRAY_LEN(ary), mid; int smaller = 0, satisfied = 0; VALUE v, val; RETURN_ENUMERATOR(ary, 0, 0); while (low < high) { mid = low + ((high - low) / 2); val = rb_ary_entry(ary, mid); v = rb_yield(val); if (FIXNUM_P(v)) { if (v == INT2FIX(0)) return INT2FIX(mid); smaller = (SIGNED_VALUE)v < 0; /* Fixnum preserves its sign-bit */ } else if (v == Qtrue) { satisfied = 1; smaller = 1; } else if (!RTEST(v)) { smaller = 0; } else if (rb_obj_is_kind_of(v, rb_cNumeric)) { const VALUE zero = INT2FIX(0); switch (rb_cmpint(rb_funcallv(v, id_cmp, 1, &zero), v, zero)) { case 0: return INT2FIX(mid); case 1: smaller = 0; break; case -1: smaller = 1; } } else { rb_raise(rb_eTypeError, "wrong argument type %"PRIsVALUE " (must be numeric, true, false or nil)", rb_obj_class(v)); } if (smaller) { high = mid; } else { low = mid + 1; } } if (!satisfied) return Qnil; return INT2FIX(low); }
从self
中删除所有元素
a = [:foo, 'bar', 2] a.clear # => []
VALUE rb_ary_clear(VALUE ary) { rb_ary_modify_check(ary); if (ARY_SHARED_P(ary)) { if (!ARY_EMBED_P(ary)) { rb_ary_unshare(ary); FL_SET_EMBED(ary); ARY_SET_EMBED_LEN(ary, 0); } } else { ARY_SET_LEN(ary, 0); if (ARY_DEFAULT_SIZE * 2 < ARY_CAPA(ary)) { ary_resize_capa(ary, ARY_DEFAULT_SIZE * 2); } } ary_verify(ary); return ary; }
如果给出,则使用self
的每个元素调用块;返回一个新的数组,其元素是块的返回值
a = [:foo, 'bar', 2] a1 = a.map {|element| element.class } a1 # => [Symbol, String, Integer]
如果未给出块,则返回一个新的Enumerator
a = [:foo, 'bar', 2] a1 = a.map a1 # => #<Enumerator: [:foo, "bar", 2]:map>
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; }
如果给出,则使用每个元素调用块;用块的返回值替换元素
a = [:foo, 'bar', 2] a.map! { |element| element.class } # => [Symbol, String, Integer]
如果未给出块,则返回一个新的Enumerator
a = [:foo, 'bar', 2] a1 = a.map! a1 # => #<Enumerator: [:foo, "bar", 2]:map!>
static VALUE rb_ary_collect_bang(VALUE ary) { long i; RETURN_SIZED_ENUMERATOR(ary, 0, 0, ary_enum_length); rb_ary_modify(ary); for (i = 0; i < RARRAY_LEN(ary); i++) { rb_ary_store(ary, i, rb_yield(RARRAY_AREF(ary, i))); } return ary; }
如果给出,则使用self
的元素组合调用块;返回self
。组合的顺序是不确定的。
当给出块和一个范围内的正Integer
参数n
(0 < n <= self.size
)时,使用self
的所有n
元组组合调用块。
示例
a = [0, 1, 2] a.combination(2) {|combination| p combination }
输出
[0, 1] [0, 2] [1, 2]
另一个示例
a = [0, 1, 2] a.combination(3) {|combination| p combination }
输出
[0, 1, 2]
当n
为零时,使用一个新的空数组调用块一次
a = [0, 1, 2] a1 = a.combination(0) {|combination| p combination }
输出
[]
当n
超出范围(负数或大于self.size
)时,不调用块
a = [0, 1, 2] a.combination(-1) {|combination| fail 'Cannot happen' } a.combination(4) {|combination| fail 'Cannot happen' }
如果未给出块,则返回一个新的Enumerator
a = [0, 1, 2] a.combination(2) # => #<Enumerator: [0, 1, 2]:combination(2)>
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; }
返回一个新数组,包含来自self
的所有非nil
元素。
a = [nil, 0, nil, 1, nil, 2, nil] a.compact # => [0, 1, 2]
static VALUE rb_ary_compact(VALUE ary) { ary = rb_ary_dup(ary); rb_ary_compact_bang(ary); return ary; }
从self
中移除所有nil
元素。
如果移除任何元素,则返回self
,否则返回nil
。
static VALUE rb_ary_compact_bang(VALUE ary) { VALUE *p, *t, *end; long n; rb_ary_modify(ary); p = t = (VALUE *)RARRAY_CONST_PTR(ary); /* WB: no new reference */ end = p + RARRAY_LEN(ary); while (t < end) { if (NIL_P(*t)) t++; else *p++ = *t++; } n = p - RARRAY_CONST_PTR(ary); if (RARRAY_LEN(ary) == n) { return Qnil; } ary_resize_smaller(ary, n); return ary; }
将other_arrays
中每个数组的所有元素添加到array
中;返回self
。
a = [0, 1] a.concat([2, 3], [4, 5]) # => [0, 1, 2, 3, 4, 5]
static VALUE rb_ary_concat_multi(int argc, VALUE *argv, VALUE ary) { rb_ary_modify_check(ary); if (argc == 1) { rb_ary_concat(ary, argv[0]); } else if (argc > 1) { int i; VALUE args = rb_ary_hidden_new(argc); for (i = 0; i < argc; i++) { rb_ary_concat(args, argv[i]); } ary_append(ary, args); } ary_verify(ary); return ary; }
返回指定元素的计数。
没有参数且没有块,返回所有元素的计数。
[0, 1, 2].count # => 3 [].count # => 0
带有参数obj
,返回==
到obj
的元素的计数。
[0, 1, 2, 0.0].count(0) # => 2 [0, 1, 2].count(3) # => 0
没有参数且给定块,使用每个元素调用块;返回块返回真值的元素的计数。
[0, 1, 2, 3].count {|element| element > 1} # => 2
带有参数obj
且给定块,会发出警告,忽略块,并返回==
到obj
的元素的计数。
static VALUE rb_ary_count(int argc, VALUE *argv, VALUE ary) { long i, n = 0; if (rb_check_arity(argc, 0, 1) == 0) { VALUE v; if (!rb_block_given_p()) return LONG2NUM(RARRAY_LEN(ary)); for (i = 0; i < RARRAY_LEN(ary); i++) { v = RARRAY_AREF(ary, i); if (RTEST(rb_yield(v))) n++; } } else { VALUE obj = argv[0]; if (rb_block_given_p()) { rb_warn("given block not used"); } for (i = 0; i < RARRAY_LEN(ary); i++) { if (rb_equal(RARRAY_AREF(ary, i), obj)) n++; } } return LONG2NUM(n); }
当使用正Integer
参数count
和块调用时,使用每个元素调用块,然后再次执行此操作,直到执行count
次;返回nil
。
output = [] [0, 1].cycle(2) {|element| output.push(element) } # => nil output # => [0, 1, 0, 1]
如果count
为零或负数,则不调用块。
[0, 1].cycle(0) {|element| fail 'Cannot happen' } # => nil [0, 1].cycle(-1) {|element| fail 'Cannot happen' } # => nil
当给定块且省略参数或为nil
时,无限循环。
# Prints 0 and 1 forever. [0, 1].cycle {|element| puts element } [0, 1].cycle(nil) {|element| puts element }
当没有给定块时,返回一个新的枚举器。
[0, 1].cycle(2) # => #<Enumerator: [0, 1]:cycle(2)> [0, 1].cycle # => # => #<Enumerator: [0, 1]:cycle> [0, 1].cycle.first(5) # => [0, 1, 0, 1, 0]
static VALUE rb_ary_cycle(int argc, VALUE *argv, VALUE ary) { long n, i; rb_check_arity(argc, 0, 1); RETURN_SIZED_ENUMERATOR(ary, argc, argv, rb_ary_cycle_size); if (argc == 0 || NIL_P(argv[0])) { n = -1; } else { n = NUM2LONG(argv[0]); if (n <= 0) return Qnil; } while (RARRAY_LEN(ary) > 0 && (n < 0 || 0 < n--)) { for (i=0; i<RARRAY_LEN(ary); i++) { rb_yield(RARRAY_AREF(ary, i)); } } return Qnil; }
从self
中移除零个或多个元素。
当没有给定块时,从self
中移除每个元素ele
,使得ele == obj
;返回最后删除的元素。
s1 = 'bar'; s2 = 'bar' a = [:foo, s1, 2, s2] a.delete('bar') # => "bar" a # => [:foo, 2]
如果没有删除元素,则返回 nil
。
当给出代码块时,从 self
中删除每个满足 ele == obj
的元素 ele
。
如果找到任何此类元素,则忽略代码块并返回最后一个删除的元素。
s1 = 'bar'; s2 = 'bar' a = [:foo, s1, 2, s2] deleted_obj = a.delete('bar') {|obj| fail 'Cannot happen' } a # => [:foo, 2]
如果没有找到此类元素,则返回代码块的返回值。
a = [:foo, 'bar', 2] a.delete(:nosuch) {|obj| "#{obj} not found" } # => "nosuch not found"
VALUE rb_ary_delete(VALUE ary, VALUE item) { VALUE v = item; long i1, i2; for (i1 = i2 = 0; i1 < RARRAY_LEN(ary); i1++) { VALUE e = RARRAY_AREF(ary, i1); if (rb_equal(e, item)) { v = e; continue; } if (i1 != i2) { rb_ary_store(ary, i2, e); } i2++; } if (RARRAY_LEN(ary) == i2) { if (rb_block_given_p()) { return rb_yield(item); } return Qnil; } ary_resize_smaller(ary, i2); ary_verify(ary); return v; }
根据给定的 Integer
index
从 self
中删除一个元素。
当 index
非负时,删除偏移量为 index
的元素。
a = [:foo, 'bar', 2] a.delete_at(1) # => "bar" a # => [:foo, 2]
如果 index
太大,则返回 nil
。
当 index
为负数时,从数组末尾开始倒数。
a = [:foo, 'bar', 2] a.delete_at(-2) # => "bar" a # => [:foo, 2]
如果 index
太小(距离零太远),则返回 nil。
static VALUE rb_ary_delete_at_m(VALUE ary, VALUE pos) { return rb_ary_delete_at(ary, NUM2LONG(pos)); }
删除 self
中每个代码块返回真值的元素;返回 self
。
a = [:foo, 'bar', 2, 'bat'] a.delete_if {|element| element.to_s.start_with?('b') } # => [:foo, 2]
如果未给出块,则返回一个新的Enumerator
a = [:foo, 'bar', 2] a.delete_if # => #<Enumerator: [:foo, "bar", 2]:delete_if>
static VALUE rb_ary_delete_if(VALUE ary) { ary_verify(ary); RETURN_SIZED_ENUMERATOR(ary, 0, 0, ary_enum_length); ary_reject_bang(ary); return ary; }
返回一个新数组,该数组仅包含 self
中未在任何 other_arrays
数组中找到的元素;使用 eql?
进行比较;保留来自 self
的顺序。
[0, 1, 1, 2, 1, 1, 3, 1, 1].difference([1]) # => [0, 2, 3] [0, 1, 2, 3].difference([3, 0], [1, 3]) # => [2] [0, 1, 2].difference([4]) # => [0, 1, 2]
如果没有给出参数,则返回 self
的副本。
相关:Array#-
.
static VALUE rb_ary_difference_multi(int argc, VALUE *argv, VALUE ary) { VALUE ary_diff; long i, length; volatile VALUE t0; bool *is_hash = ALLOCV_N(bool, t0, argc); ary_diff = rb_ary_new(); length = RARRAY_LEN(ary); for (i = 0; i < argc; i++) { argv[i] = to_ary(argv[i]); is_hash[i] = (length > SMALL_ARRAY_LEN && RARRAY_LEN(argv[i]) > SMALL_ARRAY_LEN); if (is_hash[i]) argv[i] = ary_make_hash(argv[i]); } for (i = 0; i < RARRAY_LEN(ary); i++) { int j; VALUE elt = rb_ary_elt(ary, i); for (j = 0; j < argc; j++) { if (is_hash[j]) { if (rb_hash_stlike_lookup(argv[j], RARRAY_AREF(ary, i), NULL)) break; } else { if (rb_ary_includes_by_eql(argv[j], elt)) break; } } if (j == argc) rb_ary_push(ary_diff, elt); } ALLOCV_END(t0); return ary_diff; }
查找并返回嵌套对象中由 index
和 identifiers
指定的对象。嵌套对象可以是各种类的实例。参见 Dig Methods.
示例
a = [:foo, [:bar, :baz, [:bat, :bam]]] a.dig(1) # => [:bar, :baz, [:bat, :bam]] a.dig(1, 2) # => [:bat, :bam] a.dig(1, 2, 0) # => :bat a.dig(1, 2, 3) # => nil
static VALUE rb_ary_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); }
返回一个新数组,该数组包含 self
的前 n
个元素以外的所有元素,其中 n
是一个非负的 Integer
;不修改 self
。
示例
a = [0, 1, 2, 3, 4, 5] a.drop(0) # => [0, 1, 2, 3, 4, 5] a.drop(1) # => [1, 2, 3, 4, 5] a.drop(2) # => [2, 3, 4, 5]
static VALUE rb_ary_drop(VALUE ary, VALUE n) { VALUE result; long pos = NUM2LONG(n); if (pos < 0) { rb_raise(rb_eArgError, "attempt to drop negative size"); } result = rb_ary_subseq(ary, pos, RARRAY_LEN(ary)); if (NIL_P(result)) result = rb_ary_new(); return result; }
返回一个新数组,该数组包含 self
的零个或多个尾部元素;不修改 self
。
如果给出代码块,则使用 self
的每个后续元素调用代码块;如果代码块返回 false
或 nil
,则停止;返回一个新数组,省略代码块返回真值的那些元素。
a = [0, 1, 2, 3, 4, 5] a.drop_while {|element| element < 3 } # => [3, 4, 5]
如果没有给出代码块,则返回一个新的 Enumerator
[0, 1].drop_while # => # => #<Enumerator: [0, 1]:drop_while>
static VALUE rb_ary_drop_while(VALUE ary) { long i; RETURN_ENUMERATOR(ary, 0, 0); for (i = 0; i < RARRAY_LEN(ary); i++) { if (!RTEST(rb_yield(RARRAY_AREF(ary, i)))) break; } return rb_ary_drop(ary, LONG2FIX(i)); }
遍历数组元素。
当给出代码块时,将每个连续的数组元素传递给代码块;返回 self
a = [:foo, 'bar', 2] a.each {|element| puts "#{element.class} #{element}" }
输出
Symbol foo String bar Integer 2
允许在迭代期间修改数组
a = [:foo, 'bar', 2] a.each {|element| puts element; a.clear if element.to_s.start_with?('b') }
输出
foo bar
如果没有给出代码块,则返回一个新的 Enumerator
a = [:foo, 'bar', 2] e = a.each e # => #<Enumerator: [:foo, "bar", 2]:each> a1 = e.each {|element| puts "#{element.class} #{element}" }
输出
Symbol foo String bar Integer 2
VALUE rb_ary_each(VALUE ary) { long i; ary_verify(ary); RETURN_SIZED_ENUMERATOR(ary, 0, 0, ary_enum_length); for (i=0; i<RARRAY_LEN(ary); i++) { rb_yield(RARRAY_AREF(ary, i)); } return ary; }
遍历数组索引。
当给出代码块时,将每个连续的数组索引传递给代码块;返回 self
a = [:foo, 'bar', 2] a.each_index {|index| puts "#{index} #{a[index]}" }
输出
0 foo 1 bar 2 2
允许在迭代期间修改数组
a = [:foo, 'bar', 2] a.each_index {|index| puts index; a.clear if index > 0 }
输出
0 1
如果没有给出代码块,则返回一个新的 Enumerator
a = [:foo, 'bar', 2] e = a.each_index e # => #<Enumerator: [:foo, "bar", 2]:each_index> a1 = e.each {|index| puts "#{index} #{a[index]}"}
输出
0 foo 1 bar 2 2
相关:each
,reverse_each
.
static VALUE rb_ary_each_index(VALUE ary) { long i; RETURN_SIZED_ENUMERATOR(ary, 0, 0, ary_enum_length); for (i=0; i<RARRAY_LEN(ary); i++) { rb_yield(LONG2NUM(i)); } return ary; }
如果 self
中的元素数量为零,则返回 true
,否则返回 false
。
static VALUE rb_ary_empty_p(VALUE ary) { return RBOOL(RARRAY_LEN(ary) == 0); }
如果 self
和 other_array
的大小相同,并且对于 self
中的每个索引 i
,self[i].eql? other_array[i]
,则返回 true
。
a0 = [:foo, 'bar', 2] a1 = [:foo, 'bar', 2] a1.eql?(a0) # => true
否则,返回 false
。
此方法不同于方法 Array#==
,后者使用方法 Object#==
进行比较。
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); }
返回偏移量为 index
的元素。
使用单个 Integer
参数 index
,返回偏移量为 index
的元素
a = [:foo, 'bar', 2] a.fetch(1) # => "bar"
如果 index
为负数,则从数组末尾开始计数
a = [:foo, 'bar', 2] a.fetch(-1) # => 2 a.fetch(-2) # => "bar"
使用参数 index
和 default_value
,如果索引在范围内,则返回偏移量为 index
的元素,否则返回 default_value
a = [:foo, 'bar', 2] a.fetch(1, nil) # => "bar"
使用参数 index
和代码块,如果索引在范围内(并且不调用代码块),则返回偏移量为 index
的元素;否则使用索引调用代码块并返回其返回值
a = [:foo, 'bar', 2] a.fetch(1) {|index| raise 'Cannot happen' } # => "bar" a.fetch(50) {|index| "Value for #{index}" } # => "Value for 50"
static VALUE rb_ary_fetch(int argc, VALUE *argv, VALUE ary) { VALUE pos, ifnone; long block_given; long idx; rb_scan_args(argc, argv, "11", &pos, &ifnone); block_given = rb_block_given_p(); if (block_given && argc == 2) { rb_warn("block supersedes default value argument"); } idx = NUM2LONG(pos); if (idx < 0) { idx += RARRAY_LEN(ary); } if (idx < 0 || RARRAY_LEN(ary) <= idx) { if (block_given) return rb_yield(pos); if (argc == 1) { rb_raise(rb_eIndexError, "index %ld outside of array bounds: %ld...%ld", idx - (idx < 0 ? RARRAY_LEN(ary) : 0), -RARRAY_LEN(ary), RARRAY_LEN(ary)); } return ifnone; } return RARRAY_AREF(ary, idx); }
用指定的对象替换self
中的指定元素;返回self
。
如果给出参数obj
但没有给出代码块,则用该对象替换所有元素。
a = ['a', 'b', 'c', 'd'] a # => ["a", "b", "c", "d"] a.fill(:X) # => [:X, :X, :X, :X]
如果给出参数obj
和Integer
start
,但没有给出代码块,则根据给定的起始位置替换元素。
如果start
在范围内 (0 <= start < array.size
),则替换从偏移量start
到末尾的所有元素。
a = ['a', 'b', 'c', 'd'] a.fill(:X, 2) # => ["a", "b", :X, :X]
如果start
过大 (start >= array.size
),则不执行任何操作。
a = ['a', 'b', 'c', 'd'] a.fill(:X, 4) # => ["a", "b", "c", "d"] a = ['a', 'b', 'c', 'd'] a.fill(:X, 5) # => ["a", "b", "c", "d"]
如果start
为负数,则从末尾开始计数(起始索引为start + array.size
)。
a = ['a', 'b', 'c', 'd'] a.fill(:X, -2) # => ["a", "b", :X, :X]
如果start
过小(小于零且远离零),则替换所有元素。
a = ['a', 'b', 'c', 'd'] a.fill(:X, -6) # => [:X, :X, :X, :X] a = ['a', 'b', 'c', 'd'] a.fill(:X, -50) # => [:X, :X, :X, :X]
如果给出参数obj
、Integer
start
和Integer
length
,但没有给出代码块,则根据给定的start
和length
替换元素。
如果start
在范围内,则替换从偏移量start
开始的length
个元素。
a = ['a', 'b', 'c', 'd'] a.fill(:X, 1, 1) # => ["a", :X, "c", "d"]
如果start
为负数,则从末尾开始计数。
a = ['a', 'b', 'c', 'd'] a.fill(:X, -2, 1) # => ["a", "b", :X, "d"]
如果start
过大 (start >= array.size
),则用nil
扩展self
。
a = ['a', 'b', 'c', 'd'] a.fill(:X, 5, 0) # => ["a", "b", "c", "d", nil] a = ['a', 'b', 'c', 'd'] a.fill(:X, 5, 2) # => ["a", "b", "c", "d", nil, :X, :X]
如果length
为零或负数,则不替换任何元素。
a = ['a', 'b', 'c', 'd'] a.fill(:X, 1, 0) # => ["a", "b", "c", "d"] a.fill(:X, 1, -1) # => ["a", "b", "c", "d"]
如果给出参数obj
和Range
range
,但没有给出代码块,则根据给定的范围替换元素。
如果范围为正且递增 (0 < range.begin <= range.end
),则替换从range.begin
到range.end
的元素。
a = ['a', 'b', 'c', 'd'] a.fill(:X, (1..1)) # => ["a", :X, "c", "d"]
如果range.first
为负数,则不替换任何元素。
a = ['a', 'b', 'c', 'd'] a.fill(:X, (-1..1)) # => ["a", "b", "c", "d"]
如果range.last
为负数,则从末尾开始计数。
a = ['a', 'b', 'c', 'd'] a.fill(:X, (0..-2)) # => [:X, :X, :X, "d"] a = ['a', 'b', 'c', 'd'] a.fill(:X, (1..-2)) # => ["a", :X, :X, "d"]
如果range.last
和range.last
都为负数,则都从数组末尾开始计数。
a = ['a', 'b', 'c', 'd'] a.fill(:X, (-1..-1)) # => ["a", "b", "c", :X] a = ['a', 'b', 'c', 'd'] a.fill(:X, (-2..-2)) # => ["a", "b", :X, "d"]
如果没有给出参数但给出代码块,则用每个索引调用代码块;用代码块的返回值替换相应的元素。
a = ['a', 'b', 'c', 'd'] a.fill { |index| "new_#{index}" } # => ["new_0", "new_1", "new_2", "new_3"]
如果给出参数start
和代码块,则用从偏移量start
到末尾的每个索引调用代码块;用代码块的返回值替换相应的元素。
如果start在范围内 (0 <= start < array.size
),则替换从偏移量start
到末尾的元素。
a = ['a', 'b', 'c', 'd'] a.fill(1) { |index| "new_#{index}" } # => ["a", "new_1", "new_2", "new_3"]
如果start
过大(start >= array.size
),则不执行任何操作。
a = ['a', 'b', 'c', 'd'] a.fill(4) { |index| fail 'Cannot happen' } # => ["a", "b", "c", "d"] a = ['a', 'b', 'c', 'd'] a.fill(4) { |index| fail 'Cannot happen' } # => ["a", "b", "c", "d"]
如果start
为负数,则从末尾开始计数。
a = ['a', 'b', 'c', 'd'] a.fill(-2) { |index| "new_#{index}" } # => ["a", "b", "new_2", "new_3"]
如果start过小 (start <= -array.size
,则替换所有元素。
a = ['a', 'b', 'c', 'd'] a.fill(-6) { |index| "new_#{index}" } # => ["new_0", "new_1", "new_2", "new_3"] a = ['a', 'b', 'c', 'd'] a.fill(-50) { |index| "new_#{index}" } # => ["new_0", "new_1", "new_2", "new_3"]
如果给出参数start
和length
以及代码块,则用start length指定的每个索引调用代码块;用代码块的返回值替换相应的元素。
如果start
在范围内,则替换从偏移量start
开始的length
个元素。
a = ['a', 'b', 'c', 'd'] a.fill(1, 1) { |index| "new_#{index}" } # => ["a", "new_1", "c", "d"]
如果 `start` 为负数,则从末尾开始计数
a = ['a', 'b', 'c', 'd'] a.fill(-2, 1) { |index| "new_#{index}" } # => ["a", "b", "new_2", "d"]
如果start
过大 (start >= array.size
),则用nil
扩展self
。
a = ['a', 'b', 'c', 'd'] a.fill(5, 0) { |index| "new_#{index}" } # => ["a", "b", "c", "d", nil] a = ['a', 'b', 'c', 'd'] a.fill(5, 2) { |index| "new_#{index}" } # => ["a", "b", "c", "d", nil, "new_5", "new_6"]
如果 `length` 为零或更小,则不替换任何元素
a = ['a', 'b', 'c', 'd'] a.fill(1, 0) { |index| "new_#{index}" } # => ["a", "b", "c", "d"] a.fill(1, -1) { |index| "new_#{index}" } # => ["a", "b", "c", "d"]
使用参数 `obj` 和 `range` 以及给定的代码块,使用给定范围内的每个索引调用代码块;用代码块的返回值替换相应的元素。
如果范围为正且递增(`range 0 < range.begin <= range.end`),则替换从 `range.begin` 到 `range.end` 的元素
a = ['a', 'b', 'c', 'd'] a.fill(1..1) { |index| "new_#{index}" } # => ["a", "new_1", "c", "d"]
如果 `range.first` 为负数,则不执行任何操作
a = ['a', 'b', 'c', 'd'] a.fill(-1..1) { |index| fail 'Cannot happen' } # => ["a", "b", "c", "d"]
如果range.last
为负数,则从末尾开始计数。
a = ['a', 'b', 'c', 'd'] a.fill(0..-2) { |index| "new_#{index}" } # => ["new_0", "new_1", "new_2", "d"] a = ['a', 'b', 'c', 'd'] a.fill(1..-2) { |index| "new_#{index}" } # => ["a", "new_1", "new_2", "d"]
如果 `range.first` 和 `range.last` 都为负数,则两者都从末尾开始计数
a = ['a', 'b', 'c', 'd'] a.fill(-1..-1) { |index| "new_#{index}" } # => ["a", "b", "c", "new_3"] a = ['a', 'b', 'c', 'd'] a.fill(-2..-2) { |index| "new_#{index}" } # => ["a", "b", "new_2", "d"]
static VALUE rb_ary_fill(int argc, VALUE *argv, VALUE ary) { VALUE item = Qundef, arg1, arg2; long beg = 0, end = 0, len = 0; if (rb_block_given_p()) { rb_scan_args(argc, argv, "02", &arg1, &arg2); argc += 1; /* hackish */ } else { rb_scan_args(argc, argv, "12", &item, &arg1, &arg2); } switch (argc) { case 1: beg = 0; len = RARRAY_LEN(ary); break; case 2: if (rb_range_beg_len(arg1, &beg, &len, RARRAY_LEN(ary), 1)) { break; } /* fall through */ case 3: beg = NIL_P(arg1) ? 0 : NUM2LONG(arg1); if (beg < 0) { beg = RARRAY_LEN(ary) + beg; if (beg < 0) beg = 0; } len = NIL_P(arg2) ? RARRAY_LEN(ary) - beg : NUM2LONG(arg2); break; } rb_ary_modify(ary); if (len < 0) { return ary; } if (beg >= ARY_MAX_SIZE || len > ARY_MAX_SIZE - beg) { rb_raise(rb_eArgError, "argument too big"); } end = beg + len; if (RARRAY_LEN(ary) < end) { if (end >= ARY_CAPA(ary)) { ary_resize_capa(ary, end); } ary_mem_clear(ary, RARRAY_LEN(ary), end - RARRAY_LEN(ary)); ARY_SET_LEN(ary, end); } if (UNDEF_P(item)) { VALUE v; long i; for (i=beg; i<end; i++) { v = rb_yield(LONG2NUM(i)); if (i>=RARRAY_LEN(ary)) break; ARY_SET(ary, i, v); } } else { ary_memfill(ary, beg, len, item); } return ary; }
如果给定,则使用 `self` 的每个元素调用代码块;返回一个新的数组,其中包含 `self` 中代码块返回真值的元素
a = [:foo, 'bar', 2, :bam] a1 = a.select {|element| element.to_s.start_with?('b') } a1 # => ["bar", :bam]
如果未给出块,则返回一个新的Enumerator
a = [:foo, 'bar', 2, :bam] a.select # => #<Enumerator: [:foo, "bar", 2, :bam]:select>
如果给定,则使用 `self` 的每个元素调用代码块;从 `self` 中删除代码块返回 `false` 或 `nil` 的元素。
如果删除了任何元素,则返回 `self`
a = [:foo, 'bar', 2, :bam] a.select! {|element| element.to_s.start_with?('b') } # => ["bar", :bam]
如果未删除任何元素,则返回 `nil`。
如果未给出块,则返回一个新的Enumerator
a = [:foo, 'bar', 2, :bam] a.select! # => #<Enumerator: [:foo, "bar", 2, :bam]:select!>
返回指定元素的索引。
当给出参数 `object` 但没有代码块时,返回第一个元素 `element` 的索引,其中 `object == element`
a = [:foo, 'bar', 2, 'bar'] a.index('bar') # => 1
如果未找到此类元素,则返回 `nil`。
当同时给出参数 `object` 和代码块时,使用每个后续元素调用代码块;返回第一个元素的索引,其中代码块返回真值
a = [:foo, 'bar', 2, 'bar'] a.index {|element| element == 'bar' } # => 1
如果代码块从未返回真值,则返回 `nil`。
当既没有参数也没有代码块时,返回一个新的枚举器
a = [:foo, 'bar', 2] e = a.index e # => #<Enumerator: [:foo, "bar", 2]:index> e.each {|element| element == 'bar' } # => 1
相关:rindex
.
static VALUE rb_ary_index(int argc, VALUE *argv, VALUE ary) { VALUE val; long i; if (argc == 0) { RETURN_ENUMERATOR(ary, 0, 0); for (i=0; i<RARRAY_LEN(ary); i++) { if (RTEST(rb_yield(RARRAY_AREF(ary, i)))) { return LONG2NUM(i); } } return Qnil; } rb_check_arity(argc, 0, 1); val = argv[0]; if (rb_block_given_p()) rb_warn("given block not used"); for (i=0; i<RARRAY_LEN(ary); i++) { VALUE e = RARRAY_AREF(ary, i); if (rb_equal(e, val)) { return LONG2NUM(i); } } return Qnil; }
返回 self
中的元素;不修改 self
。
当没有给出参数时,返回第一个元素
a = [:foo, 'bar', 2] a.first # => :foo a # => [:foo, "bar", 2]
如果 `self` 为空,则返回 `nil`。
当给出非负的 Integer
参数 `n` 时,返回一个新的数组中的前 `n` 个元素
a = [:foo, 'bar', 2] a.first(2) # => [:foo, "bar"]
如果 `n >= array.size`,则返回所有元素
a = [:foo, 'bar', 2] a.first(50) # => [:foo, "bar", 2]
如果 `n == 0`,则返回一个新的空数组
a = [:foo, 'bar', 2] a.first(0) # []
相关:last
.
# File ruby_3_3_0/array.rb, line 101 def first n = unspecified = true if Primitive.mandatory_only? Primitive.attr! :leaf Primitive.cexpr! %q{ ary_first(self) } else if unspecified Primitive.cexpr! %q{ ary_first(self) } else Primitive.cexpr! %q{ ary_take_first_or_last_n(self, NUM2LONG(n), ARY_TAKE_FIRST) } end end end
返回一个新的数组,它是 `self` 的递归扁平化
-
每个非数组元素保持不变。
-
每个数组被替换为其各个元素。
使用非负的 Integer
参数 level
,递归地展平 level
级。
a = [ 0, [ 1, [2, 3], 4 ], 5 ] a.flatten(0) # => [0, [1, [2, 3], 4], 5] a = [ 0, [ 1, [2, 3], 4 ], 5 ] a.flatten(1) # => [0, 1, [2, 3], 4, 5] a = [ 0, [ 1, [2, 3], 4 ], 5 ] a.flatten(2) # => [0, 1, 2, 3, 4, 5] a = [ 0, [ 1, [2, 3], 4 ], 5 ] a.flatten(3) # => [0, 1, 2, 3, 4, 5]
没有参数、nil
参数或负参数 level
时,展平所有级别。
a = [ 0, [ 1, [2, 3], 4 ], 5 ] a.flatten # => [0, 1, 2, 3, 4, 5] [0, 1, 2].flatten # => [0, 1, 2] a = [ 0, [ 1, [2, 3], 4 ], 5 ] a.flatten(-1) # => [0, 1, 2, 3, 4, 5] a = [ 0, [ 1, [2, 3], 4 ], 5 ] a.flatten(-2) # => [0, 1, 2, 3, 4, 5] [0, 1, 2].flatten(-1) # => [0, 1, 2]
static VALUE rb_ary_flatten(int argc, VALUE *argv, VALUE ary) { int level = -1; VALUE result; if (rb_check_arity(argc, 0, 1) && !NIL_P(argv[0])) { level = NUM2INT(argv[0]); if (level == 0) return ary_make_shared_copy(ary); } result = flatten(ary, level); if (result == ary) { result = ary_make_shared_copy(ary); } return result; }
用 self
中每个嵌套数组的元素替换它们;如果存在任何更改,则返回 self
,否则返回 nil
。
使用非负的 Integer
参数 level
,递归地展平 level
级。
a = [ 0, [ 1, [2, 3], 4 ], 5 ] a.flatten!(1) # => [0, 1, [2, 3], 4, 5] a = [ 0, [ 1, [2, 3], 4 ], 5 ] a.flatten!(2) # => [0, 1, 2, 3, 4, 5] a = [ 0, [ 1, [2, 3], 4 ], 5 ] a.flatten!(3) # => [0, 1, 2, 3, 4, 5] [0, 1, 2].flatten!(1) # => nil
没有参数、nil
参数或负参数 level
时,展平所有级别。
a = [ 0, [ 1, [2, 3], 4 ], 5 ] a.flatten! # => [0, 1, 2, 3, 4, 5] [0, 1, 2].flatten! # => nil a = [ 0, [ 1, [2, 3], 4 ], 5 ] a.flatten!(-1) # => [0, 1, 2, 3, 4, 5] a = [ 0, [ 1, [2, 3], 4 ], 5 ] a.flatten!(-2) # => [0, 1, 2, 3, 4, 5] [0, 1, 2].flatten!(-1) # => nil
static VALUE rb_ary_flatten_bang(int argc, VALUE *argv, VALUE ary) { int mod = 0, level = -1; VALUE result, lv; lv = (rb_check_arity(argc, 0, 1) ? argv[0] : Qnil); rb_ary_modify_check(ary); if (!NIL_P(lv)) level = NUM2INT(lv); if (level == 0) return Qnil; result = flatten(ary, level); if (result == ary) { return Qnil; } if (!(mod = ARY_EMBED_P(result))) rb_obj_freeze(result); rb_ary_replace(ary, result); if (mod) ARY_SET_EMBED_LEN(result, 0); return ary; }
返回 self
的整数哈希值。
两个具有相同内容的数组将具有相同的哈希码(并且将使用 eql? 进行比较)。
[0, 1, 2].hash == [0, 1, 2].hash # => true [0, 1, 2].hash == [0, 1, 3].hash # => false
static VALUE rb_ary_hash(VALUE ary) { return rb_ary_hash_values(RARRAY_LEN(ary), RARRAY_CONST_PTR(ary)); }
如果 self
中的某个索引 i
满足 obj == self[i]
,则返回 true
;否则返回 false
。
[0, 1, 2].include?(2) # => true [0, 1, 2].include?(3) # => false
VALUE rb_ary_includes(VALUE ary, VALUE item) { long i; VALUE e; for (i=0; i<RARRAY_LEN(ary); i++) { e = RARRAY_AREF(ary, i); if (rb_equal(e, item)) { return Qtrue; } } return Qfalse; }
返回指定元素的索引。
当给出参数 `object` 但没有代码块时,返回第一个元素 `element` 的索引,其中 `object == element`
a = [:foo, 'bar', 2, 'bar'] a.index('bar') # => 1
如果未找到此类元素,则返回 `nil`。
当同时给出参数 `object` 和代码块时,使用每个后续元素调用代码块;返回第一个元素的索引,其中代码块返回真值
a = [:foo, 'bar', 2, 'bar'] a.index {|element| element == 'bar' } # => 1
如果代码块从未返回真值,则返回 `nil`。
当既没有参数也没有代码块时,返回一个新的枚举器
a = [:foo, 'bar', 2] e = a.index e # => #<Enumerator: [:foo, "bar", 2]:index> e.each {|element| element == 'bar' } # => 1
相关:rindex
.
用 other_array
的内容替换 self
的内容;返回 self
。
a = [:foo, 'bar', 2] a.replace(['foo', :bar, 3]) # => ["foo", :bar, 3]
VALUE rb_ary_replace(VALUE copy, VALUE orig) { rb_ary_modify_check(copy); orig = to_ary(orig); if (copy == orig) return copy; rb_ary_reset(copy); /* orig has enough space to embed the contents of orig. */ if (RARRAY_LEN(orig) <= ary_embed_capa(copy)) { assert(ARY_EMBED_P(copy)); ary_memcpy(copy, 0, RARRAY_LEN(orig), RARRAY_CONST_PTR(orig)); ARY_SET_EMBED_LEN(copy, RARRAY_LEN(orig)); } /* orig is embedded but copy does not have enough space to embed the * contents of orig. */ else if (ARY_EMBED_P(orig)) { long len = ARY_EMBED_LEN(orig); VALUE *ptr = ary_heap_alloc(len); FL_UNSET_EMBED(copy); ARY_SET_PTR(copy, ptr); ARY_SET_LEN(copy, len); ARY_SET_CAPA(copy, len); // No allocation and exception expected that could leave `copy` in a // bad state from the edits above. ary_memcpy(copy, 0, len, RARRAY_CONST_PTR(orig)); } /* Otherwise, orig is on heap and copy does not have enough space to embed * the contents of orig. */ else { VALUE shared_root = ary_make_shared(orig); FL_UNSET_EMBED(copy); ARY_SET_PTR(copy, ARY_HEAP_PTR(orig)); ARY_SET_LEN(copy, ARY_HEAP_LEN(orig)); rb_ary_set_shared(copy, shared_root); } ary_verify(copy); return copy; }
在 Integer
索引 offset
处的元素之前或之后插入给定的 objects
;返回 self
。
当 index
非负时,在偏移量 index
处的元素之前插入所有给定的 objects
。
a = [:foo, 'bar', 2] a.insert(1, :bat, :bam) # => [:foo, :bat, :bam, "bar", 2]
如果 index
超出数组范围(index >= self.size
),则扩展数组。
a = [:foo, 'bar', 2] a.insert(5, :bat, :bam) a # => [:foo, "bar", 2, nil, nil, :bat, :bam]
如果没有给出对象,则不执行任何操作。
a = [:foo, 'bar', 2] a.insert(1) a.insert(50) a.insert(-50) a # => [:foo, "bar", 2]
当 index
为负时,在偏移量 index+self.size
处的元素之后插入所有给定的 objects
。
a = [:foo, 'bar', 2] a.insert(-2, :bat, :bam) a # => [:foo, "bar", :bat, :bam, 2]
static VALUE rb_ary_insert(int argc, VALUE *argv, VALUE ary) { long pos; rb_check_arity(argc, 1, UNLIMITED_ARGUMENTS); rb_ary_modify_check(ary); pos = NUM2LONG(argv[0]); if (argc == 1) return ary; if (pos == -1) { pos = RARRAY_LEN(ary); } else if (pos < 0) { long minpos = -RARRAY_LEN(ary) - 1; if (pos < minpos) { rb_raise(rb_eIndexError, "index %ld too small for array; minimum: %ld", pos, minpos); } pos++; } rb_ary_splice(ary, pos, 0, argv + 1, argc - 1); return ary; }
返回通过对每个数组元素调用方法 #inspect
形成的新 String
。
a = [:foo, 'bar', 2] a.inspect # => "[:foo, \"bar\", 2]"
static VALUE rb_ary_inspect(VALUE ary) { if (RARRAY_LEN(ary) == 0) return rb_usascii_str_new2("[]"); return rb_exec_recursive(inspect_ary, ary, 0); }
如果数组和 other_ary
至少有一个共同元素,则返回 true
,否则返回 false
。
a = [ 1, 2, 3 ] b = [ 3, 4, 5 ] c = [ 5, 6, 7 ] a.intersect?(b) #=> true a.intersect?(c) #=> false
Array
元素使用 eql?
进行比较(项目还必须正确实现 hash
)。
static VALUE rb_ary_intersect_p(VALUE ary1, VALUE ary2) { VALUE hash, v, result, shorter, longer; st_data_t vv; long i; ary2 = to_ary(ary2); if (RARRAY_LEN(ary1) == 0 || RARRAY_LEN(ary2) == 0) return Qfalse; if (RARRAY_LEN(ary1) <= SMALL_ARRAY_LEN && RARRAY_LEN(ary2) <= SMALL_ARRAY_LEN) { for (i=0; i<RARRAY_LEN(ary1); i++) { v = RARRAY_AREF(ary1, i); if (rb_ary_includes_by_eql(ary2, v)) return Qtrue; } return Qfalse; } shorter = ary1; longer = ary2; if (RARRAY_LEN(ary1) > RARRAY_LEN(ary2)) { longer = ary1; shorter = ary2; } hash = ary_make_hash(shorter); result = Qfalse; for (i=0; i<RARRAY_LEN(longer); i++) { v = RARRAY_AREF(longer, i); vv = (st_data_t)v; if (rb_hash_stlike_lookup(hash, vv, 0)) { result = Qtrue; break; } } return result; }
返回一个新的数组,其中包含在 self
和所有给定的数组 other_arrays
中都找到的每个元素;重复项被省略;项目使用 eql?
进行比较(项目还必须正确实现 hash
)。
[0, 1, 2, 3].intersection([0, 1, 2], [0, 1, 3]) # => [0, 1] [0, 0, 1, 1, 2, 3].intersection([0, 1, 2], [0, 1, 3]) # => [0, 1]
保留来自self
的顺序
[0, 1, 2].intersection([2, 1, 0]) # => [0, 1, 2]
如果没有给出参数,则返回 self
的副本。
相关:Array#&.
static VALUE rb_ary_intersection_multi(int argc, VALUE *argv, VALUE ary) { VALUE result = rb_ary_dup(ary); int i; for (i = 0; i < argc; i++) { result = rb_ary_and(result, argv[i]); } return result; }
返回通过将数组元素转换后连接形成的新String
。对于每个元素element
-
如果
element
不是kind_of?(Array)
,则使用element.to_s
。 -
如果
element
是kind_of?(Array)
,则使用递归element.join(separator)
。
没有参数,使用输出字段分隔符$,
连接。
a = [:foo, 'bar', 2] $, # => nil a.join # => "foobar2"
使用字符串参数separator
,使用该分隔符连接。
a = [:foo, 'bar', 2] a.join("\n") # => "foo\nbar\n2"
递归地连接嵌套数组。
a = [:foo, [:bar, [:baz, :bat]]] a.join # => "foobarbazbat"
static VALUE rb_ary_join_m(int argc, VALUE *argv, VALUE ary) { VALUE sep; if (rb_check_arity(argc, 0, 1) == 0 || NIL_P(sep = argv[0])) { sep = rb_output_fs; if (!NIL_P(sep)) { rb_category_warn(RB_WARN_CATEGORY_DEPRECATED, "$, is set to non-nil value"); } } return rb_ary_join(ary, sep); }
保留块返回真值的元素;删除所有其他元素;返回self
。
a = [:foo, 'bar', 2, :bam] a.keep_if {|element| element.to_s.start_with?('b') } # => ["bar", :bam]
如果未给出块,则返回一个新的Enumerator
a = [:foo, 'bar', 2, :bam] a.keep_if # => #<Enumerator: [:foo, "bar", 2, :bam]:keep_if>
static VALUE rb_ary_keep_if(VALUE ary) { RETURN_SIZED_ENUMERATOR(ary, 0, 0, ary_enum_length); rb_ary_select_bang(ary); return ary; }
返回来自self
的元素;self
不会被修改。
如果没有给出参数,则返回最后一个元素。
a = [:foo, 'bar', 2] a.last # => 2 a # => [:foo, "bar", 2]
如果 `self` 为空,则返回 `nil`。
当给出非负Integer
参数n
时,返回一个新数组中的最后n
个元素。
a = [:foo, 'bar', 2] a.last(2) # => ["bar", 2]
如果 `n >= array.size`,则返回所有元素
a = [:foo, 'bar', 2] a.last(50) # => [:foo, "bar", 2]
如果n == 0
,则返回一个新的空数组。
a = [:foo, 'bar', 2] a.last(0) # []
相关:first
.
# File ruby_3_3_0/array.rb, line 145 def last n = unspecified = true if Primitive.mandatory_only? Primitive.attr! :leaf Primitive.cexpr! %q{ ary_last(self) } else if unspecified Primitive.cexpr! %q{ ary_last(self) } else Primitive.cexpr! %q{ ary_take_first_or_last_n(self, NUM2LONG(n), ARY_TAKE_LAST) } end end end
返回self
中元素的数量。
static VALUE rb_ary_length(VALUE ary) { long len = RARRAY_LEN(ary); return LONG2NUM(len); }
如果给出,则使用self
的每个元素调用块;返回一个新的数组,其元素是块的返回值
a = [:foo, 'bar', 2] a1 = a.map {|element| element.class } a1 # => [Symbol, String, Integer]
如果未给出块,则返回一个新的Enumerator
a = [:foo, 'bar', 2] a1 = a.map a1 # => #<Enumerator: [:foo, "bar", 2]:map>
如果给出,则使用每个元素调用块;用块的返回值替换元素
a = [:foo, 'bar', 2] a.map! { |element| element.class } # => [Symbol, String, Integer]
如果未给出块,则返回一个新的Enumerator
a = [:foo, 'bar', 2] a1 = a.map! a1 # => #<Enumerator: [:foo, "bar", 2]:map!>
返回以下之一
-
来自
self
的最大值元素。 -
从
self
中选择的最大值元素的新数组。
当没有给出块时,self
中的每个元素都必须对方法<=>
响应一个Integer
。
如果没有参数和代码块,则返回self
中根据<=>
方法具有最大值的元素。
[0, 1, 2].max # => 2
如果有一个参数Integer
n
,但没有代码块,则返回一个新的数组,该数组最多包含n
个元素,并根据<=>
方法以降序排列。
[0, 1, 2, 3].max(3) # => [3, 2, 1] [0, 1, 2, 3].max(6) # => [3, 2, 1, 0]
如果给出了代码块,则代码块必须返回一个Integer
。
如果有一个代码块但没有参数,则调用代码块self.size-1
次以比较元素;返回根据代码块具有最大值的元素。
['0', '00', '000'].max {|a, b| a.size <=> b.size } # => "000"
如果有一个参数n
和一个代码块,则返回一个新的数组,该数组最多包含n
个元素,并根据代码块以降序排列。
['0', '00', '000'].max(2) {|a, b| a.size <=> b.size } # => ["000", "00"]
static VALUE rb_ary_max(int argc, VALUE *argv, VALUE ary) { VALUE result = Qundef, v; VALUE num; long i; if (rb_check_arity(argc, 0, 1) && !NIL_P(num = argv[0])) return rb_nmin_run(ary, num, 0, 1, 1); const long n = RARRAY_LEN(ary); if (rb_block_given_p()) { for (i = 0; i < RARRAY_LEN(ary); i++) { v = RARRAY_AREF(ary, i); if (UNDEF_P(result) || rb_cmpint(rb_yield_values(2, v, result), v, result) > 0) { result = v; } } } else if (n > 0) { result = RARRAY_AREF(ary, 0); if (n > 1) { if (FIXNUM_P(result) && CMP_OPTIMIZABLE(INTEGER)) { return ary_max_opt_fixnum(ary, 1, result); } else if (STRING_P(result) && CMP_OPTIMIZABLE(STRING)) { return ary_max_opt_string(ary, 1, result); } else if (RB_FLOAT_TYPE_P(result) && CMP_OPTIMIZABLE(FLOAT)) { return ary_max_opt_float(ary, 1, result); } else { return ary_max_generic(ary, 1, result); } } } if (UNDEF_P(result)) return Qnil; return result; }
返回以下之一
-
self
中最小值的元素。 -
从
self
中选出的最小值元素的新数组。
当没有给出块时,self
中的每个元素都必须对方法<=>
响应一个Integer
。
如果没有参数和代码块,则返回self
中根据<=>
方法具有最小值的元素。
[0, 1, 2].min # => 0
如果有一个Integer
参数n
,但没有代码块,则返回一个新的数组,该数组最多包含n
个元素,并根据<=>
方法以升序排列。
[0, 1, 2, 3].min(3) # => [0, 1, 2] [0, 1, 2, 3].min(6) # => [0, 1, 2, 3]
如果给出了代码块,则代码块必须返回一个Integer
。
如果有一个代码块但没有参数,则调用代码块self.size-1
次以比较元素;返回根据代码块具有最小值的元素。
['0', '00', '000'].min { |a, b| a.size <=> b.size } # => "0"
如果有一个参数n
和一个代码块,则返回一个新的数组,该数组最多包含n
个元素,并根据代码块以升序排列。
['0', '00', '000'].min(2) {|a, b| a.size <=> b.size } # => ["0", "00"]
static VALUE rb_ary_min(int argc, VALUE *argv, VALUE ary) { VALUE result = Qundef, v; VALUE num; long i; if (rb_check_arity(argc, 0, 1) && !NIL_P(num = argv[0])) return rb_nmin_run(ary, num, 0, 0, 1); const long n = RARRAY_LEN(ary); if (rb_block_given_p()) { for (i = 0; i < RARRAY_LEN(ary); i++) { v = RARRAY_AREF(ary, i); if (UNDEF_P(result) || rb_cmpint(rb_yield_values(2, v, result), v, result) < 0) { result = v; } } } else if (n > 0) { result = RARRAY_AREF(ary, 0); if (n > 1) { if (FIXNUM_P(result) && CMP_OPTIMIZABLE(INTEGER)) { return ary_min_opt_fixnum(ary, 1, result); } else if (STRING_P(result) && CMP_OPTIMIZABLE(STRING)) { return ary_min_opt_string(ary, 1, result); } else if (RB_FLOAT_TYPE_P(result) && CMP_OPTIMIZABLE(FLOAT)) { return ary_min_opt_float(ary, 1, result); } else { return ary_min_generic(ary, 1, result); } } } if (UNDEF_P(result)) return Qnil; return result; }
返回一个新的包含两个元素的数组,其中包含self
中的最小值和最大值,可以根据<=>
方法或给定的代码块进行比较。
如果没有给出代码块,则self
中的每个元素都必须对<=>
方法做出响应,并返回一个Integer
;返回一个新的包含两个元素的数组,其中包含self
中的最小值和最大值,根据<=>
方法进行比较。
[0, 1, 2].minmax # => [0, 2]
如果给出了代码块,则代码块必须返回一个Integer
;代码块被调用self.size-1
次以比较元素;返回一个新的包含两个元素的数组,其中包含self
中的最小值和最大值,根据代码块进行比较。
['0', '00', '000'].minmax {|a, b| a.size <=> b.size } # => ["0", "000"]
static VALUE rb_ary_minmax(VALUE ary) { if (rb_block_given_p()) { return rb_call_super(0, NULL); } return rb_assoc_new(rb_ary_min(0, 0, ary), rb_ary_max(0, 0, ary)); }
如果self
中没有元素满足给定的条件,则返回true
。
如果没有给出代码块和参数,则如果self
没有真值元素,则返回true
,否则返回false
。
[nil, false].none? # => true [nil, 0, false].none? # => false [].none? # => true
如果给出了代码块但没有参数,则使用self
中的每个元素调用代码块;如果代码块没有返回真值,则返回true
,否则返回false
。
[0, 1, 2].none? {|element| element > 3 } # => true [0, 1, 2].none? {|element| element > 1 } # => false
如果给出了参数obj
,则如果obj.===
没有元素,则返回true
,否则返回false
。
['food', 'drink'].none?(/bar/) # => true ['food', 'drink'].none?(/foo/) # => false [].none?(/foo/) # => true [0, 1, 2].none?(3) # => true [0, 1, 2].none?(1) # => false
static VALUE rb_ary_none_p(int argc, VALUE *argv, VALUE ary) { long i, len = RARRAY_LEN(ary); rb_check_arity(argc, 0, 1); if (!len) return Qtrue; if (argc) { if (rb_block_given_p()) { rb_warn("given block not used"); } for (i = 0; i < RARRAY_LEN(ary); ++i) { if (RTEST(rb_funcall(argv[0], idEqq, 1, RARRAY_AREF(ary, i)))) return Qfalse; } } else if (!rb_block_given_p()) { for (i = 0; i < len; ++i) { if (RTEST(RARRAY_AREF(ary, i))) return Qfalse; } } else { for (i = 0; i < RARRAY_LEN(ary); ++i) { if (RTEST(rb_yield(RARRAY_AREF(ary, i)))) return Qfalse; } } return Qtrue; }
如果 self
中恰好只有一个元素满足给定条件,则返回 true
。
如果没有给出代码块且没有参数,如果 self
恰好只有一个真值元素,则返回 true
,否则返回 false
[nil, 0].one? # => true [0, 0].one? # => false [nil, nil].one? # => false [].one? # => false
如果给出代码块但没有参数,则使用 self
中的每个元素调用代码块;如果代码块对恰好一个元素返回真值,则返回 true
,否则返回 false
[0, 1, 2].one? {|element| element > 0 } # => false [0, 1, 2].one? {|element| element > 1 } # => true [0, 1, 2].one? {|element| element > 2 } # => false
如果给出参数 obj
,如果 obj.===
恰好一个元素,则返回 true
,否则返回 false
[0, 1, 2].one?(0) # => true [0, 0, 1].one?(0) # => false [1, 1, 2].one?(0) # => false ['food', 'drink'].one?(/bar/) # => false ['food', 'drink'].one?(/foo/) # => true [].one?(/foo/) # => false
static VALUE rb_ary_one_p(int argc, VALUE *argv, VALUE ary) { long i, len = RARRAY_LEN(ary); VALUE result = Qfalse; rb_check_arity(argc, 0, 1); if (!len) return Qfalse; if (argc) { if (rb_block_given_p()) { rb_warn("given block not used"); } for (i = 0; i < RARRAY_LEN(ary); ++i) { if (RTEST(rb_funcall(argv[0], idEqq, 1, RARRAY_AREF(ary, i)))) { if (result) return Qfalse; result = Qtrue; } } } else if (!rb_block_given_p()) { for (i = 0; i < len; ++i) { if (RTEST(RARRAY_AREF(ary, i))) { if (result) return Qfalse; result = Qtrue; } } } else { for (i = 0; i < RARRAY_LEN(ary); ++i) { if (RTEST(rb_yield(RARRAY_AREF(ary, i)))) { if (result) return Qfalse; result = Qtrue; } } } return result; }
将 self
中的每个元素格式化为二进制字符串;返回该字符串。参见 打包数据.
# File ruby_3_3_0/pack.rb, line 7 def pack(fmt, buffer: nil) Primitive.pack_pack(fmt, buffer) end
当使用代码块调用时,生成 self
元素的所有排列;返回 self
。排列的顺序是不确定的。
当给出代码块和一个范围内的正 Integer
参数 n
(0 < n <= self.size
) 时,使用 self
的所有 n
元组排列调用代码块。
示例
a = [0, 1, 2] a.permutation(2) {|permutation| p permutation }
输出
[0, 1] [0, 2] [1, 0] [1, 2] [2, 0] [2, 1]
另一个示例
a = [0, 1, 2] a.permutation(3) {|permutation| p permutation }
输出
[0, 1, 2] [0, 2, 1] [1, 0, 2] [1, 2, 0] [2, 0, 1] [2, 1, 0]
当n
为零时,使用一个新的空数组调用块一次
a = [0, 1, 2] a.permutation(0) {|permutation| p permutation }
输出
[]
当n
超出范围(负数或大于self.size
)时,不调用块
a = [0, 1, 2] a.permutation(-1) {|permutation| fail 'Cannot happen' } a.permutation(4) {|permutation| fail 'Cannot happen' }
当给出代码块但没有参数时,行为与 a.permutation(a.size)
相同
a = [0, 1, 2] a.permutation {|permutation| p permutation }
输出
[0, 1, 2] [0, 2, 1] [1, 0, 2] [1, 2, 0] [2, 0, 1] [2, 1, 0]
如果未给出块,则返回一个新的Enumerator
a = [0, 1, 2] a.permutation # => #<Enumerator: [0, 1, 2]:permutation> a.permutation(2) # => #<Enumerator: [0, 1, 2]:permutation(2)>
static VALUE rb_ary_permutation(int argc, VALUE *argv, VALUE ary) { long r, n, i; n = RARRAY_LEN(ary); /* Array length */ RETURN_SIZED_ENUMERATOR(ary, argc, argv, rb_ary_permutation_size); /* Return enumerator if no block */ r = n; if (rb_check_arity(argc, 0, 1) && !NIL_P(argv[0])) r = NUM2LONG(argv[0]); /* Permutation size from argument */ if (r < 0 || n < r) { /* no permutations: yield nothing */ } else if (r == 0) { /* exactly one permutation: the zero-length array */ rb_yield(rb_ary_new2(0)); } else if (r == 1) { /* this is a special, easy case */ for (i = 0; i < RARRAY_LEN(ary); i++) { rb_yield(rb_ary_new3(1, RARRAY_AREF(ary, i))); } } else { /* this is the general case */ volatile VALUE t0; long *p = ALLOCV_N(long, t0, r+roomof(n, sizeof(long))); char *used = (char*)(p + r); VALUE ary0 = ary_make_shared_copy(ary); /* private defensive copy of ary */ RBASIC_CLEAR_CLASS(ary0); MEMZERO(used, char, n); /* initialize array */ permute0(n, r, p, used, ary0); /* compute and yield permutations */ ALLOCV_END(t0); RBASIC_SET_CLASS_RAW(ary0, rb_cArray); } return ary; }
移除并返回尾部元素。
如果没有给出参数且 self
不为空,则移除并返回最后一个元素
a = [:foo, 'bar', 2] a.pop # => 2 a # => [:foo, "bar"]
如果数组为空,则返回 nil
。
当给出非负 Integer
参数 n
且在范围内时,
移除并返回最后一个 n
个元素,这些元素位于一个新的数组中
a = [:foo, 'bar', 2] a.pop(2) # => ["bar", 2]
如果 n
为正且超出范围,则移除并返回所有元素
a = [:foo, 'bar', 2] a.pop(50) # => [:foo, "bar", 2]
static VALUE rb_ary_pop_m(int argc, VALUE *argv, VALUE ary) { VALUE result; if (argc == 0) { return rb_ary_pop(ary); } rb_ary_modify_check(ary); result = ary_take_first_or_last(argc, argv, ary, ARY_TAKE_LAST); ARY_INCREASE_LEN(ary, -RARRAY_LEN(result)); ary_verify(ary); return result; }
将给定的 objects
预置到 self
中
a = [:foo, 'bar', 2] a.unshift(:bam, :bat) # => [:bam, :bat, :foo, "bar", 2]
计算并返回或生成所有来自所有数组的元素组合,包括 self
和 other_arrays
。
-
组合的数量是所有数组大小的乘积,包括
self
和other_arrays
。 -
返回的组合的顺序是不确定的。
当没有给出代码块时,返回组合作为数组的数组。
a = [0, 1, 2] a1 = [3, 4] a2 = [5, 6] p = a.product(a1) p.size # => 6 # a.size * a1.size p # => [[0, 3], [0, 4], [1, 3], [1, 4], [2, 3], [2, 4]] p = a.product(a1, a2) p.size # => 12 # a.size * a1.size * a2.size p # => [[0, 3, 5], [0, 3, 6], [0, 4, 5], [0, 4, 6], [1, 3, 5], [1, 3, 6], [1, 4, 5], [1, 4, 6], [2, 3, 5], [2, 3, 6], [2, 4, 5], [2, 4, 6]]
如果任何参数是空数组,则返回空数组。
如果没有给出参数,则返回一个包含 1 个元素的数组的数组,每个数组包含 self
的一个元素。
a.product # => [[0], [1], [2]]
当给出代码块时,将每个组合作为数组生成;返回 self
。
a.product(a1) {|combination| p combination }
输出
[0, 3] [0, 4] [1, 3] [1, 4] [2, 3] [2, 4]
如果任何参数是空数组,则不调用代码块。
a.product(a1, a2, []) {|combination| fail 'Cannot happen' }
如果没有给出参数,则将 self
的每个元素作为 1 个元素的数组生成。
a.product {|combination| p combination }
输出
[0] [1] [2]
static VALUE rb_ary_product(int argc, VALUE *argv, VALUE ary) { int n = argc+1; /* How many arrays we're operating on */ volatile VALUE t0 = rb_ary_hidden_new(n); volatile VALUE t1 = Qundef; VALUE *arrays = RARRAY_PTR(t0); /* The arrays we're computing the product of */ int *counters = ALLOCV_N(int, t1, n); /* The current position in each one */ VALUE result = Qnil; /* The array we'll be returning, when no block given */ long i,j; long resultlen = 1; RBASIC_CLEAR_CLASS(t0); /* initialize the arrays of arrays */ ARY_SET_LEN(t0, n); arrays[0] = ary; for (i = 1; i < n; i++) arrays[i] = Qnil; for (i = 1; i < n; i++) arrays[i] = to_ary(argv[i-1]); /* initialize the counters for the arrays */ for (i = 0; i < n; i++) counters[i] = 0; /* Otherwise, allocate and fill in an array of results */ if (rb_block_given_p()) { /* Make defensive copies of arrays; exit if any is empty */ for (i = 0; i < n; i++) { if (RARRAY_LEN(arrays[i]) == 0) goto done; arrays[i] = ary_make_shared_copy(arrays[i]); } } else { /* Compute the length of the result array; return [] if any is empty */ for (i = 0; i < n; i++) { long k = RARRAY_LEN(arrays[i]); if (k == 0) { result = rb_ary_new2(0); goto done; } if (MUL_OVERFLOW_LONG_P(resultlen, k)) rb_raise(rb_eRangeError, "too big to product"); resultlen *= k; } result = rb_ary_new2(resultlen); } for (;;) { int m; /* fill in one subarray */ VALUE subarray = rb_ary_new2(n); for (j = 0; j < n; j++) { rb_ary_push(subarray, rb_ary_entry(arrays[j], counters[j])); } /* put it on the result array */ if (NIL_P(result)) { FL_SET(t0, RARRAY_SHARED_ROOT_FLAG); rb_yield(subarray); if (!FL_TEST(t0, RARRAY_SHARED_ROOT_FLAG)) { rb_raise(rb_eRuntimeError, "product reentered"); } else { FL_UNSET(t0, RARRAY_SHARED_ROOT_FLAG); } } else { rb_ary_push(result, subarray); } /* * Increment the last counter. If it overflows, reset to 0 * and increment the one before it. */ m = n-1; counters[m]++; while (counters[m] == RARRAY_LEN(arrays[m])) { counters[m] = 0; /* If the first counter overflows, we are done */ if (--m < 0) goto done; counters[m]++; } } done: ALLOCV_END(t1); return NIL_P(result) ? ary : result; }
追加尾部元素。
将 objects
中的每个参数追加到 self
中;返回 self
a = [:foo, 'bar', 2] a.push(:baz, :bat) # => [:foo, "bar", 2, :baz, :bat]
将每个参数追加为一个元素,即使它是另一个数组
a = [:foo, 'bar', 2] a1 = a.push([:baz, :bat], [:bam, :bad]) a1 # => [:foo, "bar", 2, [:baz, :bat], [:bam, :bad]]
static VALUE rb_ary_push_m(int argc, VALUE *argv, VALUE ary) { return rb_ary_cat(ary, argv, argc); }
返回 self
中第一个元素,该元素是一个数组,其第二个元素 ==
obj
。
a = [{foo: 0}, [2, 4], [4, 5, 6], [4, 5]] a.rassoc(4) # => [2, 4]
如果找不到这样的元素,则返回nil
。
相关:assoc
.
VALUE rb_ary_rassoc(VALUE ary, VALUE value) { long i; VALUE v; for (i = 0; i < RARRAY_LEN(ary); ++i) { v = rb_check_array_type(RARRAY_AREF(ary, i)); if (RB_TYPE_P(v, T_ARRAY) && RARRAY_LEN(v) > 1 && rb_equal(RARRAY_AREF(v, 1), value)) return v; } return Qnil; }
返回一个新的数组,其元素是 self
中所有代码块返回 false
或 nil
的元素。
a = [:foo, 'bar', 2, 'bat'] a1 = a.reject {|element| element.to_s.start_with?('b') } a1 # => [:foo, 2]
如果未给出块,则返回一个新的Enumerator
a = [:foo, 'bar', 2] a.reject # => #<Enumerator: [:foo, "bar", 2]:reject>
static VALUE rb_ary_reject(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
。
a = [:foo, 'bar', 2, 'bat'] a.reject! {|element| element.to_s.start_with?('b') } # => [:foo, 2]
如果没有删除元素,则返回 nil
。
如果未给出块,则返回一个新的Enumerator
a = [:foo, 'bar', 2] a.reject! # => #<Enumerator: [:foo, "bar", 2]:reject!>
static VALUE rb_ary_reject_bang(VALUE ary) { RETURN_SIZED_ENUMERATOR(ary, 0, 0, ary_enum_length); rb_ary_modify(ary); return ary_reject_bang(ary); }
使用 self
元素的每个长度为 n
的重复组合调用代码块;每个组合都是一个数组;返回 self
。组合的顺序是不确定的。
当给出代码块和一个正的 Integer
参数 n
时,使用 self
元素的每个 n
元组重复组合调用代码块。组合的数量是 (n+1)(n+2)/2
。
n
= 1:
a = [0, 1, 2] a.repeated_combination(1) {|combination| p combination }
输出
[0] [1] [2]
n
= 2:
a.repeated_combination(2) {|combination| p combination }
输出
[0, 0] [0, 1] [0, 2] [1, 1] [1, 2] [2, 2]
如果 n
为零,则使用空数组调用块一次。
如果 n
为负数,则不调用块。
a.repeated_combination(-1) {|combination| fail 'Cannot happen' }
如果未给出块,则返回一个新的Enumerator
a = [0, 1, 2] a.repeated_combination(2) # => #<Enumerator: [0, 1, 2]:combination(2)>
使用枚举器,可以方便地显示一些 n
值的组合和计数。
e = a.repeated_combination(0) e.size # => 1 e.to_a # => [[]] e = a.repeated_combination(1) e.size # => 3 e.to_a # => [[0], [1], [2]] e = a.repeated_combination(2) e.size # => 6 e.to_a # => [[0, 0], [0, 1], [0, 2], [1, 1], [1, 2], [2, 2]]
static VALUE rb_ary_repeated_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; }
使用 self
元素的长度为 n
的每个重复排列调用块;每个排列都是一个数组;返回 self
。排列的顺序是不确定的。
当给出块和正 Integer
参数 n
时,使用 self
元素的每个 n
元组重复排列调用块。排列的数量为 self.size**n
。
n
= 1:
a = [0, 1, 2] a.repeated_permutation(1) {|permutation| p permutation }
输出
[0] [1] [2]
n
= 2:
a.repeated_permutation(2) {|permutation| p permutation }
输出
[0, 0] [0, 1] [0, 2] [1, 0] [1, 1] [1, 2] [2, 0] [2, 1] [2, 2]
如果 n
为零,则使用空数组调用块一次。
如果 n
为负数,则不调用块。
a.repeated_permutation(-1) {|permutation| fail 'Cannot happen' }
如果未给出块,则返回一个新的Enumerator
a = [0, 1, 2] a.repeated_permutation(2) # => #<Enumerator: [0, 1, 2]:permutation(2)>
使用枚举器,可以方便地显示一些 n
值的排列和计数。
e = a.repeated_permutation(0) e.size # => 1 e.to_a # => [[]] e = a.repeated_permutation(1) e.size # => 3 e.to_a # => [[0], [1], [2]] e = a.repeated_permutation(2) e.size # => 9 e.to_a # => [[0, 0], [0, 1], [0, 2], [1, 0], [1, 1], [1, 2], [2, 0], [2, 1], [2, 2]]
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; }
用 other_array
的内容替换 self
的内容;返回 self
。
a = [:foo, 'bar', 2] a.replace(['foo', :bar, 3]) # => ["foo", :bar, 3]
返回一个新的数组,其中包含 self
元素的逆序。
a = ['foo', 'bar', 'two'] a1 = a.reverse a1 # => ["two", "bar", "foo"]
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 = ['foo', 'bar', 'two'] a.reverse! # => ["two", "bar", "foo"]
static VALUE rb_ary_reverse_bang(VALUE ary) { return rb_ary_reverse(ary); }
反向迭代数组元素。
当给出块时,以逆序将每个元素传递给块;返回 self
。
a = [:foo, 'bar', 2] a.reverse_each {|element| puts "#{element.class} #{element}" }
输出
Integer 2 String bar Symbol foo
允许在迭代期间修改数组
a = [:foo, 'bar', 2] a.reverse_each {|element| puts element; a.clear if element.to_s.start_with?('b') }
输出
2 bar
如果没有给出代码块,则返回一个新的 Enumerator
a = [:foo, 'bar', 2] e = a.reverse_each e # => #<Enumerator: [:foo, "bar", 2]:reverse_each> a1 = e.each {|element| puts "#{element.class} #{element}" }
输出
Integer 2 String bar Symbol foo
相关:each
,each_index
。
static VALUE rb_ary_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; }
返回 object == element
的最后一个元素的索引。
当给出参数 object
但没有块时,返回找到的最后一个此类元素的索引。
a = [:foo, 'bar', 2, 'bar'] a.rindex('bar') # => 3
如果未找到此类对象,则返回 nil
。
当给出块但没有参数时,使用每个后续元素调用块;返回块返回真值的最后一个元素的索引。
a = [:foo, 'bar', 2, 'bar'] a.rindex {|element| element == 'bar' } # => 3
如果代码块从未返回真值,则返回 `nil`。
当既没有参数也没有代码块时,返回一个新的枚举器
a = [:foo, 'bar', 2, 'bar'] e = a.rindex e # => #<Enumerator: [:foo, "bar", 2, "bar"]:rindex> e.each {|element| element == 'bar' } # => 3
相关:index
。
static VALUE rb_ary_rindex(int argc, VALUE *argv, VALUE ary) { VALUE val; long i = RARRAY_LEN(ary), len; if (argc == 0) { RETURN_ENUMERATOR(ary, 0, 0); while (i--) { if (RTEST(rb_yield(RARRAY_AREF(ary, i)))) return LONG2NUM(i); if (i > (len = RARRAY_LEN(ary))) { i = len; } } return Qnil; } rb_check_arity(argc, 0, 1); val = argv[0]; if (rb_block_given_p()) rb_warn("given block not used"); while (i--) { VALUE e = RARRAY_AREF(ary, i); if (rb_equal(e, val)) { return LONG2NUM(i); } if (i > RARRAY_LEN(ary)) { break; } } return Qnil; }
返回一个新的数组,该数组由self
形成,元素从一端旋转到另一端。
如果没有给出参数,则返回一个新的数组,该数组类似于self
,但第一个元素已旋转到最后一个位置。
a = [:foo, 'bar', 2, 'bar'] a1 = a.rotate a1 # => ["bar", 2, "bar", :foo]
如果给出了非负的Integer
count
,则返回一个新的数组,其中count
个元素从开头旋转到结尾。
a = [:foo, 'bar', 2] a1 = a.rotate(2) a1 # => [2, :foo, "bar"]
如果count
很大,则使用count % array.size
作为计数。
a = [:foo, 'bar', 2] a1 = a.rotate(20) a1 # => [2, :foo, "bar"]
如果count
为零,则返回self
的副本,未修改。
a = [:foo, 'bar', 2] a1 = a.rotate(0) a1 # => [:foo, "bar", 2]
如果给出了负的Integer
count
,则反向旋转,从结尾到开头。
a = [:foo, 'bar', 2] a1 = a.rotate(-2) a1 # => ["bar", 2, :foo]
如果count
很小(远离零),则使用count % array.size
作为计数。
a = [:foo, 'bar', 2] a1 = a.rotate(-5) a1 # => ["bar", 2, :foo]
static VALUE rb_ary_rotate_m(int argc, VALUE *argv, VALUE ary) { VALUE rotated; const VALUE *ptr; long len; long cnt = (rb_check_arity(argc, 0, 1) ? NUM2LONG(argv[0]) : 1); len = RARRAY_LEN(ary); rotated = rb_ary_new2(len); if (len > 0) { cnt = rotate_count(cnt, len); ptr = RARRAY_CONST_PTR(ary); len -= cnt; ary_memcpy(rotated, 0, len, ptr + cnt); ary_memcpy(rotated, len, cnt, ptr); } ARY_SET_LEN(rotated, RARRAY_LEN(ary)); return rotated; }
通过将元素从一端移动到另一端来就地旋转self
;返回self
。
如果没有给出参数,则将第一个元素旋转到最后一个位置。
a = [:foo, 'bar', 2, 'bar'] a.rotate! # => ["bar", 2, "bar", :foo]
如果给出了非负的Integer
count
,则将count
个元素从开头旋转到结尾。
a = [:foo, 'bar', 2] a.rotate!(2) a # => [2, :foo, "bar"]
如果count
很大,则使用count % array.size
作为计数。
a = [:foo, 'bar', 2] a.rotate!(20) a # => [2, :foo, "bar"]
如果count
为零,则返回self
未修改。
a = [:foo, 'bar', 2] a.rotate!(0) a # => [:foo, "bar", 2]
如果给出了负的Integer
count
,则反向旋转,从结尾到开头。
a = [:foo, 'bar', 2] a.rotate!(-2) a # => ["bar", 2, :foo]
如果count
很小(远离零),则使用count % array.size
作为计数。
a = [:foo, 'bar', 2] a.rotate!(-5) a # => ["bar", 2, :foo]
static VALUE rb_ary_rotate_bang(int argc, VALUE *argv, VALUE ary) { long n = (rb_check_arity(argc, 0, 1) ? NUM2LONG(argv[0]) : 1); rb_ary_rotate(ary, n); return ary; }
从self
中返回随机元素。
如果没有给出参数,则从self
中返回一个随机元素。
a = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] a.sample # => 3 a.sample # => 8
如果 `self` 为空,则返回 `nil`。
如果给出了参数n
,则返回一个新的数组,该数组包含self
中的n
个随机元素。
a.sample(3) # => [8, 9, 2] a.sample(6) # => [9, 6, 10, 3, 1, 4]
返回不超过a.size
个元素(因为没有引入新的重复项)。
a.sample(a.size * 2) # => [6, 4, 1, 8, 5, 9, 10, 2, 3, 7]
但self
可能包含重复项。
a = [1, 1, 1, 2, 2, 3] a.sample(a.size * 2) # => [1, 1, 3, 2, 1, 2]
参数n
必须是非负数值。结果数组的顺序与self
的顺序无关。如果self
为空,则返回一个新的空数组。
可选的random
参数将用作随机数生成器。
a = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] a.sample(random: Random.new(1)) #=> 6 a.sample(4, random: Random.new(1)) #=> [6, 10, 9, 2]
# File ruby_3_3_0/array.rb, line 60 def sample(n = (ary = false), random: Random) if Primitive.mandatory_only? # Primitive.cexpr! %{ rb_ary_sample(self, rb_cRandom, Qfalse, Qfalse) } Primitive.ary_sample0 else # Primitive.cexpr! %{ rb_ary_sample(self, random, n, ary) } Primitive.ary_sample(random, n, ary) end end
如果给定,则使用 `self` 的每个元素调用代码块;返回一个新的数组,其中包含 `self` 中代码块返回真值的元素
a = [:foo, 'bar', 2, :bam] a1 = a.select {|element| element.to_s.start_with?('b') } a1 # => ["bar", :bam]
如果未给出块,则返回一个新的Enumerator
a = [:foo, 'bar', 2, :bam] a.select # => #<Enumerator: [:foo, "bar", 2, :bam]:select>
static VALUE rb_ary_select(VALUE ary) { VALUE result; long i; RETURN_SIZED_ENUMERATOR(ary, 0, 0, ary_enum_length); result = rb_ary_new2(RARRAY_LEN(ary)); for (i = 0; i < RARRAY_LEN(ary); i++) { if (RTEST(rb_yield(RARRAY_AREF(ary, i)))) { rb_ary_push(result, rb_ary_elt(ary, i)); } } return result; }
如果给定,则使用 `self` 的每个元素调用代码块;从 `self` 中删除代码块返回 `false` 或 `nil` 的元素。
如果删除了任何元素,则返回 `self`
a = [:foo, 'bar', 2, :bam] a.select! {|element| element.to_s.start_with?('b') } # => ["bar", :bam]
如果未删除任何元素,则返回 `nil`。
如果未给出块,则返回一个新的Enumerator
a = [:foo, 'bar', 2, :bam] a.select! # => #<Enumerator: [:foo, "bar", 2, :bam]:select!>
static VALUE rb_ary_select_bang(VALUE ary) { struct select_bang_arg args; RETURN_SIZED_ENUMERATOR(ary, 0, 0, ary_enum_length); rb_ary_modify(ary); args.ary = ary; args.len[0] = args.len[1] = 0; return rb_ensure(select_bang_i, (VALUE)&args, select_bang_ensure, (VALUE)&args); }
移除并返回开头元素。
如果没有参数,移除并返回第一个元素。
a = [:foo, 'bar', 2] a.shift # => :foo a # => ['bar', 2]
如果 self
为空,则返回 nil
。
当给出正整数参数 n
时,移除前 n
个元素;将这些元素返回到一个新的数组中。
a = [:foo, 'bar', 2] a.shift(2) # => [:foo, 'bar'] a # => [2]
如果 n
大于或等于 self.length
,则移除所有元素;将这些元素返回到一个新的数组中。
a = [:foo, 'bar', 2] a.shift(3) # => [:foo, 'bar', 2]
如果 n
为零,则返回一个新的空数组;self
不变。
static VALUE rb_ary_shift_m(int argc, VALUE *argv, VALUE ary) { VALUE result; long n; if (argc == 0) { return rb_ary_shift(ary); } rb_ary_modify_check(ary); result = ary_take_first_or_last(argc, argv, ary, ARY_TAKE_FIRST); n = RARRAY_LEN(result); rb_ary_behead(ary,n); return result; }
返回一个新的数组,其中包含 self
的元素,这些元素已被打乱。
a = [1, 2, 3] #=> [1, 2, 3] a.shuffle #=> [2, 3, 1] a #=> [1, 2, 3]
可选的random
参数将用作随机数生成器。
a.shuffle(random: Random.new(1)) #=> [1, 3, 2]
# File ruby_3_3_0/array.rb, line 26 def shuffle(random: Random) Primitive.rb_ary_shuffle(random) end
就地打乱 self
的元素。
a = [1, 2, 3] #=> [1, 2, 3] a.shuffle! #=> [2, 3, 1] a #=> [2, 3, 1]
可选的random
参数将用作随机数生成器。
a.shuffle!(random: Random.new(1)) #=> [1, 3, 2]
# File ruby_3_3_0/array.rb, line 12 def shuffle!(random: Random) Primitive.rb_ary_shuffle_bang(random) end
返回 self
中的元素;不修改 self
。
当给定单个 Integer
参数 index
时,返回偏移量为 index
的元素
a = [:foo, 'bar', 2] a[0] # => :foo a[2] # => 2 a # => [:foo, "bar", 2]
如果 index
为负数,则相对于 self
的末尾进行计数
a = [:foo, 'bar', 2] a[-1] # => 2 a[-2] # => "bar"
如果 index
超出范围,则返回 nil
。
当给定两个 Integer
参数 start
和 length
时,返回一个新的大小为 length
的数组,其中包含从偏移量 start
开始的连续元素
a = [:foo, 'bar', 2] a[0, 2] # => [:foo, "bar"] a[1, 2] # => ["bar", 2]
如果 start + length
大于 self.length
,则返回从偏移量 start
到末尾的所有元素
a = [:foo, 'bar', 2] a[0, 4] # => [:foo, "bar", 2] a[1, 3] # => ["bar", 2] a[2, 2] # => [2]
如果 start == self.size
且 length >= 0
,则返回一个新的空数组。
如果 length
为负数,则返回 nil
。
当给定单个 Range
参数 range
时,将 range.min
视为上面的 start
,将 range.size
视为上面的 length
a = [:foo, 'bar', 2] a[0..1] # => [:foo, "bar"] a[1..2] # => ["bar", 2]
特殊情况:如果 range.start == a.size
,则返回一个新的空数组。
如果 range.end
为负数,则从末尾计算结束索引
a = [:foo, 'bar', 2] a[0..-1] # => [:foo, "bar", 2] a[0..-2] # => [:foo, "bar"] a[0..-3] # => [:foo]
如果 range.start
为负数,则从末尾计算开始索引
a = [:foo, 'bar', 2] a[-1..2] # => [2] a[-2..2] # => ["bar", 2] a[-3..2] # => [:foo, "bar", 2]
如果 range.start
大于数组大小,则返回 nil
。
a = [:foo, 'bar', 2] a[4..1] # => nil a[4..0] # => nil a[4..-1] # => nil
当给定单个 Enumerator::ArithmeticSequence
参数 aseq
时,返回一个数组,其中包含与序列生成的索引相对应的元素。
a = ['--', 'data1', '--', 'data2', '--', 'data3'] a[(1..).step(2)] # => ["data1", "data2", "data3"]
与使用范围切片不同,如果算术序列的开始或结束大于数组大小,则会抛出 RangeError
。
a = ['--', 'data1', '--', 'data2', '--', 'data3'] a[(1..11).step(2)] # RangeError (((1..11).step(2)) out of range) a[(7..).step(2)] # RangeError (((7..).step(2)) out of range)
如果给定单个参数,并且其类型不是列出的类型之一,则尝试将其转换为 Integer
,如果无法转换,则会引发异常。
a = [:foo, 'bar', 2] # Raises TypeError (no implicit conversion of Symbol into Integer): a[:foo]
从 self
中移除并返回元素。
当唯一参数是整数 n
时,移除并返回 self
中的第 n 个元素。
a = [:foo, 'bar', 2] a.slice!(1) # => "bar" a # => [:foo, 2]
如果 n
为负数,则从 self
的末尾开始反向计数。
a = [:foo, 'bar', 2] a.slice!(-1) # => 2 a # => [:foo, "bar"]
如果 n
超出范围,则返回 nil
。
当唯一参数是整数 start
和 length
时,从 self
中移除从偏移量 start
开始的 length
个元素;将删除的元素返回到一个新的数组中。
a = [:foo, 'bar', 2] a.slice!(0, 2) # => [:foo, "bar"] a # => [2]
如果 start + length
超过数组大小,则移除并返回从偏移量 start
到末尾的所有元素。
a = [:foo, 'bar', 2] a.slice!(1, 50) # => ["bar", 2] a # => [:foo]
如果 start == a.size
且 length
非负,则返回一个新的空数组。
如果 length
为负数,则返回 nil
。
当唯一参数是 Range
对象 range
时,将 range.min
视为上面的 start
,将 range.size
视为上面的 length
a = [:foo, 'bar', 2] a.slice!(1..2) # => ["bar", 2] a # => [:foo]
如果 range.start == a.size
,则返回一个新的空数组。
如果 range.start
大于数组大小,则返回 nil
。
如果 range.end
为负数,则从数组末尾倒数。
a = [:foo, 'bar', 2] a.slice!(0..-2) # => [:foo, "bar"] a # => [2]
如果 range.start
为负数,则从数组末尾倒数计算起始索引。
a = [:foo, 'bar', 2] a.slice!(-2..2) # => ["bar", 2] a # => [:foo]
static VALUE rb_ary_slice_bang(int argc, VALUE *argv, VALUE ary) { VALUE arg1; long pos, len; rb_ary_modify_check(ary); rb_check_arity(argc, 1, 2); arg1 = argv[0]; if (argc == 2) { pos = NUM2LONG(argv[0]); len = NUM2LONG(argv[1]); return ary_slice_bang_by_rb_ary_splice(ary, pos, len); } if (!FIXNUM_P(arg1)) { switch (rb_range_beg_len(arg1, &pos, &len, RARRAY_LEN(ary), 0)) { case Qtrue: /* valid range */ return ary_slice_bang_by_rb_ary_splice(ary, pos, len); case Qnil: /* invalid range */ return Qnil; default: /* not a range */ break; } } return rb_ary_delete_at(ary, NUM2LONG(arg1)); }
返回一个新的数组,其元素来自 self
,已排序。
如果没有块,则使用运算符 <=>
比较元素(参见 Comparable
)。
a = 'abcde'.split('').shuffle a # => ["e", "b", "d", "a", "c"] a1 = a.sort a1 # => ["a", "b", "c", "d", "e"]
如果有块,则使用每个元素对调用块;对于每个元素对 a
和 b
,块应返回一个整数。
-
当
b
应该在a
之后时为负数。 -
当
a
和b
相等时为零。 -
当
a
应该在b
之后时为正数。
示例
a = 'abcde'.split('').shuffle a # => ["e", "b", "d", "a", "c"] a1 = a.sort {|a, b| a <=> b } a1 # => ["a", "b", "c", "d", "e"] a2 = a.sort {|a, b| b <=> a } a2 # => ["e", "d", "c", "b", "a"]
当块返回零时,a
和 b
的顺序是不确定的,并且可能不稳定。
a = 'abcde'.split('').shuffle a # => ["e", "b", "d", "a", "c"] a1 = a.sort {|a, b| 0 } a1 # => ["c", "e", "b", "d", "a"]
VALUE rb_ary_sort(VALUE ary) { ary = rb_ary_dup(ary); rb_ary_sort_bang(ary); return ary; }
返回 self
,其元素已就地排序。
如果没有块,则使用运算符 <=>
比较元素(参见 Comparable
)。
a = 'abcde'.split('').shuffle a # => ["e", "b", "d", "a", "c"] a.sort! a # => ["a", "b", "c", "d", "e"]
如果有块,则使用每个元素对调用块;对于每个元素对 a
和 b
,块应返回一个整数。
-
当
b
应该在a
之后时为负数。 -
当
a
和b
相等时为零。 -
当
a
应该在b
之后时为正数。
示例
a = 'abcde'.split('').shuffle a # => ["e", "b", "d", "a", "c"] a.sort! {|a, b| a <=> b } a # => ["a", "b", "c", "d", "e"] a.sort! {|a, b| b <=> a } a # => ["e", "d", "c", "b", "a"]
当块返回零时,a
和 b
的顺序是不确定的,并且可能不稳定。
a = 'abcde'.split('').shuffle a # => ["e", "b", "d", "a", "c"] a.sort! {|a, b| 0 } a # => ["d", "e", "c", "a", "b"]
VALUE rb_ary_sort_bang(VALUE ary) { rb_ary_modify(ary); assert(!ARY_SHARED_P(ary)); if (RARRAY_LEN(ary) > 1) { VALUE tmp = ary_make_substitution(ary); /* only ary refers tmp */ struct ary_sort_data data; long len = RARRAY_LEN(ary); RBASIC_CLEAR_CLASS(tmp); data.ary = tmp; data.receiver = ary; RARRAY_PTR_USE(tmp, ptr, { ruby_qsort(ptr, len, sizeof(VALUE), rb_block_given_p()?sort_1:sort_2, &data); }); /* WB: no new reference */ rb_ary_modify(ary); if (ARY_EMBED_P(tmp)) { if (ARY_SHARED_P(ary)) { /* ary might be destructively operated in the given block */ rb_ary_unshare(ary); FL_SET_EMBED(ary); } ary_memcpy(ary, 0, ARY_EMBED_LEN(tmp), ARY_EMBED_PTR(tmp)); ARY_SET_LEN(ary, ARY_EMBED_LEN(tmp)); } else { if (!ARY_EMBED_P(ary) && ARY_HEAP_PTR(ary) == ARY_HEAP_PTR(tmp)) { FL_UNSET_SHARED(ary); ARY_SET_CAPA(ary, RARRAY_LEN(tmp)); } else { assert(!ARY_SHARED_P(tmp)); if (ARY_EMBED_P(ary)) { FL_UNSET_EMBED(ary); } else if (ARY_SHARED_P(ary)) { /* ary might be destructively operated in the given block */ rb_ary_unshare(ary); } else { ary_heap_free(ary); } ARY_SET_PTR(ary, ARY_HEAP_PTR(tmp)); ARY_SET_HEAP_LEN(ary, len); ARY_SET_CAPA(ary, ARY_HEAP_LEN(tmp)); } /* tmp was lost ownership for the ptr */ FL_UNSET(tmp, FL_FREEZE); FL_SET_EMBED(tmp); ARY_SET_EMBED_LEN(tmp, 0); FL_SET(tmp, FL_FREEZE); } /* tmp will be GC'ed. */ RBASIC_SET_CLASS_RAW(tmp, rb_cArray); /* rb_cArray must be marked */ } ary_verify(ary); return ary; }
就地排序 self
的元素,使用由块确定的排序;返回 self。
使用每个后续元素调用块;根据块返回的值对元素进行排序。
对于块返回的重复项,排序是不确定的,并且可能不稳定。
此示例根据字符串的大小对字符串进行排序。
a = ['aaaa', 'bbb', 'cc', 'd'] a.sort_by! {|element| element.size } a # => ["d", "cc", "bbb", "aaaa"]
如果未给出块,则返回一个新的Enumerator
a = ['aaaa', 'bbb', 'cc', 'd'] a.sort_by! # => #<Enumerator: ["aaaa", "bbb", "cc", "d"]:sort_by!>
static VALUE rb_ary_sort_by_bang(VALUE ary) { VALUE sorted; RETURN_SIZED_ENUMERATOR(ary, 0, 0, ary_enum_length); rb_ary_modify(ary); sorted = rb_block_call(ary, rb_intern("sort_by"), 0, 0, sort_by_i, 0); rb_ary_replace(ary, sorted); return ary; }
如果没有给出块,则返回等效于
sum = init array.each {|element| sum += element } sum
例如,[e1, e2, e3].sum
返回 init + e1 + e2 + e3
。
示例
a = [0, 1, 2, 3] a.sum # => 6 a.sum(100) # => 106
元素不必是数字,但必须与彼此和 init
兼容 +
。
a = ['abc', 'def', 'ghi'] a.sum('jkl') # => "jklabcdefghi"
如果给出块,则使用每个元素调用它,并且块的返回值(而不是元素本身)用作加数。
a = ['zero', 1, :two] s = a.sum('Coerced and concatenated: ') {|element| element.to_s } s # => "Coerced and concatenated: zero1two"
笔记
-
Array#join
和Array#flatten
可能比Array#sum
更快,用于字符串数组或数组数组。
static VALUE rb_ary_sum(int argc, VALUE *argv, VALUE ary) { VALUE e, v, r; long i, n; int block_given; v = (rb_check_arity(argc, 0, 1) ? argv[0] : LONG2FIX(0)); block_given = rb_block_given_p(); if (RARRAY_LEN(ary) == 0) return v; n = 0; r = Qundef; if (!FIXNUM_P(v) && !RB_BIGNUM_TYPE_P(v) && !RB_TYPE_P(v, T_RATIONAL)) { i = 0; goto init_is_a_value; } for (i = 0; i < RARRAY_LEN(ary); i++) { e = RARRAY_AREF(ary, i); if (block_given) e = rb_yield(e); if (FIXNUM_P(e)) { n += FIX2LONG(e); /* should not overflow long type */ if (!FIXABLE(n)) { v = rb_big_plus(LONG2NUM(n), v); n = 0; } } else if (RB_BIGNUM_TYPE_P(e)) v = rb_big_plus(e, v); else if (RB_TYPE_P(e, T_RATIONAL)) { if (UNDEF_P(r)) r = e; else r = rb_rational_plus(r, e); } else goto not_exact; } v = finish_exact_sum(n, r, v, argc!=0); return v; not_exact: v = finish_exact_sum(n, r, v, i!=0); if (RB_FLOAT_TYPE_P(e)) { /* * Kahan-Babuska balancing compensated summation algorithm * See https://link.springer.com/article/10.1007/s00607-005-0139-x */ double f, c; double x, t; f = NUM2DBL(v); c = 0.0; goto has_float_value; for (; i < RARRAY_LEN(ary); i++) { e = RARRAY_AREF(ary, i); if (block_given) e = rb_yield(e); if (RB_FLOAT_TYPE_P(e)) has_float_value: x = RFLOAT_VALUE(e); else if (FIXNUM_P(e)) x = FIX2LONG(e); else if (RB_BIGNUM_TYPE_P(e)) x = rb_big2dbl(e); else if (RB_TYPE_P(e, T_RATIONAL)) x = rb_num2dbl(e); else goto not_float; if (isnan(f)) continue; if (isnan(x)) { f = x; continue; } if (isinf(x)) { if (isinf(f) && signbit(x) != signbit(f)) f = NAN; else f = x; continue; } if (isinf(f)) continue; t = f + x; if (fabs(f) >= fabs(x)) c += ((f - t) + x); else c += ((x - t) + f); f = t; } f += c; return DBL2NUM(f); not_float: v = DBL2NUM(f); } goto has_some_value; init_is_a_value: for (; i < RARRAY_LEN(ary); i++) { e = RARRAY_AREF(ary, i); if (block_given) e = rb_yield(e); has_some_value: v = rb_funcall(v, idPLUS, 1, e); } return v; }
返回一个新的数组,包含 self
的前 n
个元素,其中 n
是一个非负的 Integer
;不修改 self
。
示例
a = [0, 1, 2, 3, 4, 5] a.take(1) # => [0] a.take(2) # => [0, 1] a.take(50) # => [0, 1, 2, 3, 4, 5] a # => [0, 1, 2, 3, 4, 5]
static VALUE rb_ary_take(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); }
返回一个新的数组,包含 self
的零个或多个前导元素;不修改 self
。
如果给定一个代码块,则使用 self
的每个后续元素调用该代码块;如果代码块返回 false
或 nil
,则停止;返回一个新的数组,包含代码块返回真值的那些元素。
a = [0, 1, 2, 3, 4, 5] a.take_while {|element| element < 3 } # => [0, 1, 2] a.take_while {|element| true } # => [0, 1, 2, 3, 4, 5] a # => [0, 1, 2, 3, 4, 5]
如果没有给出代码块,则返回一个新的 Enumerator
[0, 1].take_while # => #<Enumerator: [0, 1]:take_while>
static VALUE rb_ary_take_while(VALUE ary) { long i; RETURN_ENUMERATOR(ary, 0, 0); for (i = 0; i < RARRAY_LEN(ary); i++) { if (!RTEST(rb_yield(RARRAY_AREF(ary, i)))) break; } return rb_ary_take(ary, LONG2FIX(i)); }
当 self
是 Array 的实例时,返回 self
a = [:foo, 'bar', 2] a.to_a # => [:foo, "bar", 2]
否则,返回一个新的数组,包含 self
的元素。
class MyArray < Array; end a = MyArray.new(['foo', 'bar', 'two']) a.instance_of?(Array) # => false a.kind_of?(Array) # => true a1 = a.to_a a1 # => ["foo", "bar", "two"] a1.class # => Array # Not MyArray
static VALUE rb_ary_to_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
。
static VALUE rb_ary_to_ary_m(VALUE ary) { return ary; }
返回一个新的 Hash
,由 self
形成。
如果给定一个代码块,则使用每个数组元素调用该代码块;代码块必须返回一个包含两个元素的数组,这两个元素在返回的 Hash 中形成一个键值对。
a = ['foo', :bar, 1, [2, 3], {baz: 4}] h = a.to_h {|item| [item, item] } h # => {"foo"=>"foo", :bar=>:bar, 1=>1, [2, 3]=>[2, 3], {:baz=>4}=>{:baz=>4}}
如果没有给定代码块,则 self
必须是一个包含两个元素子数组的数组,每个子数组在新的 Hash 中形成一个键值对。
[].to_h # => {} a = [['foo', 'zero'], ['bar', 'one'], ['baz', 'two']] h = a.to_h h # => {"foo"=>"zero", "bar"=>"one", "baz"=>"two"}
static VALUE rb_ary_to_h(VALUE ary) { long i; VALUE hash = rb_hash_new_with_size(RARRAY_LEN(ary)); int block_given = rb_block_given_p(); for (i=0; i<RARRAY_LEN(ary); i++) { const VALUE e = rb_ary_elt(ary, i); const VALUE elt = block_given ? rb_yield_force_blockarg(e) : e; const VALUE key_value_pair = rb_check_array_type(elt); if (NIL_P(key_value_pair)) { rb_raise(rb_eTypeError, "wrong element type %"PRIsVALUE" at %ld (expected array)", rb_obj_class(elt), i); } if (RARRAY_LEN(key_value_pair) != 2) { rb_raise(rb_eArgError, "wrong array length at %ld (expected 2, was %ld)", i, RARRAY_LEN(key_value_pair)); } rb_hash_aset(hash, RARRAY_AREF(key_value_pair, 0), RARRAY_AREF(key_value_pair, 1)); } return hash; }
返回通过对每个数组元素调用方法 #inspect
形成的新 String
。
a = [:foo, 'bar', 2] a.inspect # => "[:foo, \"bar\", 2]"
转置数组数组中的行和列;嵌套数组的大小必须相同。
a = [[:a0, :a1], [:b0, :b1], [:c0, :c1]] a.transpose # => [[:a0, :b0, :c0], [:a1, :b1, :c1]]
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` 和所有给定数组 `other_arrays` 的并集;重复项将被移除;顺序保持不变;项目使用 `eql?` 进行比较。
[0, 1, 2, 3].union([4, 5], [6, 7]) # => [0, 1, 2, 3, 4, 5, 6, 7] [0, 1, 1].union([2, 1], [3, 1]) # => [0, 1, 2, 3] [0, 1, 2, 3].union([3, 2], [1, 0]) # => [0, 1, 2, 3]
如果没有给出参数,则返回 self
的副本。
相关:Array#|。
static VALUE rb_ary_union_multi(int argc, VALUE *argv, VALUE ary) { int i; long sum; VALUE hash; sum = RARRAY_LEN(ary); for (i = 0; i < argc; i++) { argv[i] = to_ary(argv[i]); sum += RARRAY_LEN(argv[i]); } if (sum <= SMALL_ARRAY_LEN) { VALUE ary_union = rb_ary_new(); rb_ary_union(ary_union, ary); for (i = 0; i < argc; i++) rb_ary_union(ary_union, argv[i]); return ary_union; } hash = ary_make_hash(ary); for (i = 0; i < argc; i++) rb_ary_union_hash(hash, argv[i]); return rb_hash_values(hash); }
返回一个新的数组,其中包含 `self` 中的非重复元素,始终保留第一次出现的元素。
如果没有给出代码块,则使用 `eql?` 方法识别并省略重复项。
a = [0, 0, 1, 1, 2, 2] a.uniq # => [0, 1, 2]
如果给出代码块,则对每个元素调用代码块;识别(使用 `eql?` 方法)并省略重复值,即代码块返回相同值的元素。
a = ['a', 'aa', 'aaa', 'b', 'bb', 'bbb'] a.uniq {|element| element.size } # => ["a", "aa", "aaa"]
static VALUE rb_ary_uniq(VALUE ary) { VALUE hash, uniq; if (RARRAY_LEN(ary) <= 1) { hash = 0; uniq = rb_ary_dup(ary); } else if (rb_block_given_p()) { hash = ary_make_hash_by(ary); uniq = rb_hash_values(hash); } else { hash = ary_make_hash(ary); uniq = rb_hash_values(hash); } return uniq; }
从 `self` 中移除重复元素,始终保留第一次出现的元素;如果移除任何元素,则返回 `self`,否则返回 `nil`。
如果没有给出代码块,则使用 `eql?` 方法识别并移除元素。
如果删除了任何元素,则返回 self
。
a = [0, 0, 1, 1, 2, 2] a.uniq! # => [0, 1, 2]
如果没有删除元素,则返回 nil
。
如果给出代码块,则对每个元素调用代码块;识别(使用 `eql?` 方法)并移除代码块返回重复值的元素。
如果删除了任何元素,则返回 self
。
a = ['a', 'aa', 'aaa', 'b', 'bb', 'bbb'] a.uniq! {|element| element.size } # => ['a', 'aa', 'aaa']
如果没有删除元素,则返回 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); rb_hash_foreach(hash, push_value, ary); return ary; }
将给定的 objects
预置到 self
中
a = [:foo, 'bar', 2] a.unshift(:bam, :bat) # => [:bam, :bat, :foo, "bar", 2]
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` 中在给定 Integer
或 Range
`indexes` 处的元素。
对于每个正 `index`,返回偏移量为 `index` 的元素。
a = [:foo, 'bar', 2] a.values_at(0, 2) # => [:foo, 2] a.values_at(0..1) # => [:foo, "bar"]
给定的 `indexes` 可以是任何顺序,并且可以重复。
a = [:foo, 'bar', 2] a.values_at(2, 0, 1, 0, 2) # => [2, :foo, "bar", :foo, 2] a.values_at(1, 0..2) # => ["bar", :foo, "bar", 2]
对于过大的 `index`,分配 `nil`。
a = [:foo, 'bar', 2] a.values_at(0, 3, 1, 3) # => [:foo, nil, "bar", nil]
如果没有给出参数,则返回一个新的空数组。
对于每个负 `index`,从数组末尾倒数。
a = [:foo, 'bar', 2] a.values_at(-1, -3) # => [2, :foo]
对于过小的 `index`,分配 `nil`。
a = [:foo, 'bar', 2] a.values_at(0, -5, 1, -6, 2) # => [:foo, nil, "bar", nil, 2]
给定的 `indexes` 可以混合正负号。
a = [:foo, 'bar', 2] a.values_at(0, -2, 1, -1) # => [:foo, "bar", "bar", 2]
static VALUE rb_ary_values_at(int argc, VALUE *argv, VALUE ary) { long i, olen = RARRAY_LEN(ary); VALUE result = rb_ary_new_capa(argc); for (i = 0; i < argc; ++i) { append_values_at_single(result, ary, olen, argv[i]); } RB_GC_GUARD(ary); return result; }
如果没有给出代码块,则返回一个新的 Array new_array
,其大小为 self.size
,其元素为 Arrays。
每个嵌套数组 new_array[n]
的大小为 other_arrays.size+1
,并且包含
-
self
的第 n 个元素。 -
每个
other_arrays
的第 n 个元素。
如果所有 other_arrays
和 self
的大小相同
a = [:a0, :a1, :a2, :a3] b = [:b0, :b1, :b2, :b3] c = [:c0, :c1, :c2, :c3] d = a.zip(b, c) d # => [[:a0, :b0, :c0], [:a1, :b1, :c1], [:a2, :b2, :c2], [:a3, :b3, :c3]]
如果 other_arrays
中的任何数组小于 self
,则用 nil
填充到 self.size
a = [:a0, :a1, :a2, :a3] b = [:b0, :b1, :b2] c = [:c0, :c1] d = a.zip(b, c) d # => [[:a0, :b0, :c0], [:a1, :b1, :c1], [:a2, :b2, nil], [:a3, nil, nil]]
如果 other_arrays
中的任何数组大于 self
,则其尾部元素将被忽略
a = [:a0, :a1, :a2, :a3] b = [:b0, :b1, :b2, :b3, :b4] c = [:c0, :c1, :c2, :c3, :c4, :c5] d = a.zip(b, c) d # => [[:a0, :b0, :c0], [:a1, :b1, :c1], [:a2, :b2, :c2], [:a3, :b3, :c3]]
如果给出代码块,则使用每个子数组(如上所述形成)调用代码块;返回 nil
a = [:a0, :a1, :a2, :a3] b = [:b0, :b1, :b2, :b3] c = [:c0, :c1, :c2, :c3] a.zip(b, c) {|sub_array| p sub_array} # => nil
输出
[:a0, :b0, :c0] [:a1, :b1, :c1] [:a2, :b2, :c2] [:a3, :b3, :c3]
static VALUE rb_ary_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; }
返回 array
和 Array other_array
的并集;重复项将被删除;顺序保持;项目使用 eql?
进行比较
[0, 1] | [2, 3] # => [0, 1, 2, 3] [0, 1, 1] | [2, 2, 3] # => [0, 1, 2, 3] [0, 1, 2] | [3, 2, 1, 0] # => [0, 1, 2, 3]
相关:Array#union
.
static VALUE rb_ary_or(VALUE ary1, VALUE ary2) { VALUE hash; ary2 = to_ary(ary2); if (RARRAY_LEN(ary1) + RARRAY_LEN(ary2) <= SMALL_ARRAY_LEN) { VALUE ary3 = rb_ary_new(); rb_ary_union(ary3, ary1); rb_ary_union(ary3, ary2); return ary3; } hash = ary_make_hash(ary1); rb_ary_union_hash(hash, ary2); return rb_hash_values(hash); }