类 Array
Array 对象是对象的有序、整数索引集合,称为元素;该对象表示数组数据结构。
一个元素可以是任何对象(甚至另一个数组);元素可以是任何不同类型对象的混合。
使用数组的重要数据结构包括
还有类似数组的数据结构
数组索引¶ ↑
与 C 或 Java 中一样,数组索引从 0 开始。
非负索引是从第一个元素的偏移量
-
索引 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]
获取有关 Array
的信息¶ ↑
数组始终跟踪自己的长度。要查询数组中包含的元素数量,请使用 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]
从 Array
中删除项¶ ↑
方法 pop
会删除数组中的最后一个元素并将其返回
arr = [1, 2, 3, 4, 5, 6] arr.pop #=> 6 arr #=> [1, 2, 3, 4, 5]
要检索并同时删除第一个项,请使用 shift
arr.shift #=> 1 arr #=> [2, 3, 4, 5]
要删除特定索引处的元素
arr.delete_at(2) #=> 4 arr #=> [2, 3, 5]
要删除数组中任何位置的特定元素,请使用 delete
arr = [1, 2, 2, 3] arr.delete(2) #=> 2 arr #=> [1,3]
如果你需要从数组中删除 nil
值,则一个有用的方法是 compact
arr = ['foo', 0, nil, 'bar', 7, 'baz', nil] arr.compact #=> ['foo', 0, 'bar', 7, 'baz'] arr #=> ['foo', 0, nil, 'bar', 7, 'baz', nil] arr.compact! #=> ['foo', 0, 'bar', 7, 'baz'] arr #=> ['foo', 0, 'bar', 7, 'baz']
另一个常见的需求是从数组中删除重复元素。
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]
从 Array
中选择项¶ ↑
可以根据代码块中定义的条件从数组中选择元素。选择操作可以是破坏性的,也可以是非破坏性的。破坏性操作会修改调用它们的数组,而非破坏性方法通常会返回一个包含所选元素的新数组,但会保持原始数组不变。
非破坏性选择¶ ↑
arr = [1, 2, 3, 4, 5, 6] arr.select {|a| a > 3} #=> [4, 5, 6] arr.reject {|a| a < 3} #=> [3, 4, 5, 6] arr.drop_while {|a| a < 4} #=> [4, 5, 6] arr #=> [1, 2, 3, 4, 5, 6]
破坏性选择¶ ↑
select!
和 reject!
分别是 select
和 reject
对应的破坏性方法。
类似于 select
与 reject
的关系,delete_if
和 keep_if
在使用相同的代码块时会产生完全相反的结果。
arr.delete_if {|a| a < 4} #=> [4, 5, 6] arr #=> [4, 5, 6] arr = [1, 2, 3, 4, 5, 6] arr.keep_if {|a| a < 4} #=> [1, 2, 3] arr #=> [1, 2, 3]
本页内容¶ ↑
首先,介绍一下其他地方的内容。Array
类
-
继承自
Object
类。 -
包含
Enumerable
模块,该模块提供了许多额外的方法。
在这里,Array
类提供了以下方面有用的方法:
创建 Array
的方法¶ ↑
-
::[]
:返回一个用给定对象填充的新数组。 -
::new
:返回一个新数组。 -
::try_convert
:返回一个从给定对象创建的新数组。
另请参阅 创建数组。
查询方法¶ ↑
-
all?
:返回是否所有元素都满足给定条件。 -
any?
:返回是否任何元素满足给定条件。 -
count
:返回满足给定条件的元素的计数。 -
empty?
:返回是否存在任何元素。 -
find_index
(别名为index
):返回满足给定条件的第一个元素的索引。 -
hash
:返回整数哈希码。 -
include?
:返回是否存在任何元素==
给定对象。 -
none?
:返回是否没有元素==
给定对象。 -
one?
:返回是否正好有一个元素==
给定对象。 -
rindex
:返回满足给定条件的最后一个元素的索引。
比较方法¶ ↑
-
#<=>: 返回 -1、0 或 1,分别表示
self
小于、等于或大于给定对象。 -
==
:返回是否self
中的每个元素==
给定对象中的对应元素。 -
eql?
:返回是否self
中的每个元素eql?
给定对象中的对应元素。
获取方法¶ ↑
这些方法不会修改 self
。
-
assoc
:返回第一个元素是数组且其第一个元素==
给定对象的元素。 -
at
:返回给定偏移量的元素。 -
bsearch
:返回通过给定代码块确定的二分搜索选择的元素。 -
bsearch_index
:返回通过给定代码块确定的二分搜索选择的元素的索引。 -
compact
:返回包含所有非nil
元素的数组。 -
dig
:返回由给定索引和其他参数指定的嵌套对象中的对象。 -
drop
:返回由给定索引确定的尾部元素。 -
drop_while
:返回由给定代码块确定的尾部元素。 -
fetch
:返回给定偏移量的元素。 -
fetch_values
:返回给定偏移量的元素。 -
first
:返回一个或多个前导元素。 -
last
:返回一个或多个尾部元素。 -
max
:返回一个或多个最大值元素,由#<=>
或给定代码块确定。 -
min
:返回一个或多个最小值元素,由#<=>
或给定代码块确定。 -
minmax
:返回最小值和最大值元素,由#<=>
或给定代码块确定。 -
rassoc
:返回第一个元素是数组且其第二个元素==
给定对象的元素。 -
reject
:返回一个包含未被给定代码块拒绝的元素的数组。 -
reverse
:返回所有元素的反向顺序。 -
rotate
:返回所有元素,其中一些元素从一端旋转到另一端。 -
sample
:返回一个或多个随机元素。 -
shuffle
:返回随机顺序的元素。 -
sort
:返回由#<=>
或给定代码块确定的顺序的所有元素。 -
take
:返回由给定索引确定的前导元素。 -
take_while
:返回由给定代码块确定的前导元素。 -
uniq
:返回包含非重复元素的数组。 -
values_at
:返回给定偏移量的元素。
赋值方法¶ ↑
这些方法会添加、替换或重新排序 self
中的元素。
-
<<
:追加一个元素。 -
[]=
:用给定对象赋值指定的元素。 -
concat
:追加给定数组中的所有元素。 -
fill
:用指定的对象替换指定的元素。 -
flatten!
:用该数组中的元素替换self
中的每个嵌套数组。 -
initialize_copy
(别名为replace
):用给定数组的内容替换self
的内容。 -
insert
:在给定偏移量处插入给定对象;不替换元素。 -
reverse!
:用其反向元素替换self
。 -
rotate!
:用其旋转元素替换self
。 -
shuffle!
:用其随机顺序的元素替换self
。 -
sort!
:用其排序后的元素替换self
,由#<=>
或给定代码块确定。 -
sort_by!
:用其排序后的元素替换self
,由给定代码块确定。
删除方法¶ ↑
这些方法都会从 self
中移除元素
-
clear
:移除所有元素。 -
compact!
:移除所有nil
元素。 -
delete
:移除等于给定对象的元素。 -
delete_at
:移除给定偏移量的元素。 -
delete_if
:移除由给定代码块指定的元素。 -
keep_if
:移除不由给定代码块指定的元素。 -
pop
:移除并返回最后一个元素。 -
reject!
:移除由给定代码块指定的元素。 -
shift
:移除并返回第一个元素。 -
slice!
:移除并返回一系列元素。 -
uniq!
:移除重复项。
组合方法¶ ↑
-
#&:返回一个包含在
self
和给定数组中都存在的元素的数组。 -
+
:返回一个包含self
的所有元素,后跟给定数组的所有元素的数组。 -
-
:返回一个包含self
中所有但不在给定数组中找到的元素的数组。 -
#|:返回一个包含
self
的所有元素和给定数组的所有元素的数组,并删除重复项。 -
difference
:返回一个包含self
中所有但不在任何给定数组中找到的元素的数组。 -
intersection
:返回一个包含self
和每个给定数组中都存在的元素的数组。 -
product
:返回或产生self
和给定数组中元素的所有组合。 -
reverse
:返回一个包含self
中所有元素的反向顺序的数组。 -
union
:返回一个包含self
的所有元素和给定数组的所有元素的数组,并删除重复项。
迭代方法¶ ↑
-
combination
:使用self
中元素的组合调用给定的块;组合不会多次使用同一个元素。 -
cycle
:使用每个元素调用给定的块,然后重复操作,执行指定的次数或无限次。 -
each
:将每个元素传递给给定的块。 -
each_index
:将每个元素的索引传递给给定的块。 -
permutation
:使用self
中元素的排列调用给定的块;排列不会多次使用同一个元素。 -
repeated_combination
:使用self
中元素的组合调用给定的块;组合可以多次使用同一个元素。 -
repeated_permutation
:使用self
中元素的排列调用给定的块;排列可以多次使用同一个元素。 -
reverse_each
:以相反的顺序将每个元素传递给给定的块。
转换方法¶ ↑
-
flatten
:返回一个数组,它是self
的递归扁平化版本。 -
join
:返回一个新的 String,其中包含由字段分隔符连接的元素。 -
to_a
:返回self
或一个包含所有元素的新数组。 -
to_ary
:返回self
。 -
to_h
:返回由元素组成的新哈希表。 -
transpose
:转置self
,它必须是一个数组的数组。 -
zip
:返回一个新的数组的数组,其中包含self
和给定的数组。
其他方法¶ ↑
公共类方法
返回一个新数组,其中填充了给定的对象
Array[1, 'a', /^A/] # => [1, "a", /^A/] Array[] # => [] Array.[](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.new # => []
如果没有块且给出了数组参数,则返回一个具有相同元素的新数组
Array.new([:foo, 'bar', 2]) # => [:foo, "bar", 2]
如果没有块且给出了整数参数,则返回一个包含给定 default_value
的多个实例的新数组
Array.new(0) # => [] Array.new(3) # => [nil, nil, nil] Array.new(2, 3) # => [3, 3]
如果给出了块,则返回一个具有给定 size
的数组;使用范围 (0...size)
中的每个 index
调用该块;返回的数组中该 index
处的元素是块的返回值
Array.new(3) {|index| "Element #{index}" } # => ["Element 0", "Element 1", "Element 2"]
对于 Ruby 新手来说,一个常见的陷阱是将表达式作为 default_value
提供
array = Array.new(2, {}) array # => [{}, {}] array[0][:a] = 1 array # => [{a: 1}, {a: 1}], as array[0] and array[1] are same object
如果你希望数组的元素是不同的,则应传递一个块
array = Array.new(2) { {} } array # => [{}, {}] array[0][:a] = 1 array # => [{a: 1}, {}], as array[0] and array[1] are different objects
如果第一个参数不是数组或整数可转换对象,则引发 TypeError
。如果第一个参数是负整数,则引发 ArgumentError
。
相关:请参阅 创建数组的方法。
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); RUBY_ASSERT(ARY_EMBED_P(ary)); RUBY_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; }
公共实例方法
返回一个新数组,其中包含 self
和 other_array
的交集;也就是说,包含在 self
和 other_array
中都找到的那些元素
[0, 1, 2, 3] & [1, 2] # => [1, 2]
省略重复项
[0, 1, 1, 0] & [0, 1] # => [0, 1]
保留 self
中的顺序
[0, 1, 2] & [3, 2, 1, 0] # => [0, 1, 2]
使用方法 #eql?
(在 self
的每个元素中定义)识别公共元素。
相关:请参阅 组合方法。
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; }
当给定非负整数参数 n
时,返回通过连接 self
的 n
个副本构建的新数组
a = ['x', 'y'] a * 3 # => ["x", "y", "x", "y", "x", "y"]
当给定字符串参数 string_separator
时,等效于 self.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; }
返回一个新数组,其中包含 self
的所有元素,后跟 other_array
的所有元素
a = [0, 1] + [2, 3] a # => [0, 1, 2, 3]
相关:请参阅 组合方法。
VALUE rb_ary_plus(VALUE x, VALUE y) { VALUE z; long len, xlen, ylen; y = to_ary(y); xlen = RARRAY_LEN(x); ylen = RARRAY_LEN(y); len = xlen + ylen; z = rb_ary_new2(len); ary_memcpy(z, 0, xlen, RARRAY_CONST_PTR(x)); ary_memcpy(z, xlen, ylen, RARRAY_CONST_PTR(y)); ARY_SET_LEN(z, len); return z; }
返回一个仅包含 self
中未在 other_array
中找到的元素的新数组;保留 self
中的顺序
[0, 1, 1, 2, 1, 1, 3, 1, 1] - [1] # => [0, 2, 3] [0, 1, 1, 2, 1, 1, 3, 1, 1] - [3, 2, 0, :foo] # => [1, 1, 1, 1, 1, 1] [0, 1, 2] - [:foo] # => [0, 1, 2]
使用方法 #eql?
(在 self
的每个元素中定义)比较元素。
相关:请参阅 组合方法。
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
[:foo, 'bar', 2] << :baz # => [:foo, "bar", 2, :baz]
将 object
作为单个元素追加,即使它是另一个数组
[:foo, 'bar', 2] << [3, 4] # => [: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; }
如果确定 self
小于、等于或大于 other_array
,则返回 -1、0 或 1。
在 (0...self.size)
中迭代每个索引 i
-
将
result[i]
计算为self[i] <=> other_array[i]
。 -
如果
result[i]
为 1,则立即返回 1[0, 1, 2] <=> [0, 0, 2] # => 1
-
如果
result[i]
为 -1,则立即返回 -1[0, 1, 2] <=> [0, 2, 2] # => -1
-
如果
result[i]
为 0,则继续。
当每个 result
为 0 时,返回 self.size <=> other_array.size
(请参阅 Integer#<=>)
[0, 1, 2] <=> [0, 1] # => 1 [0, 1, 2] <=> [0, 1, 2] # => 0 [0, 1, 2] <=> [0, 1, 2, 3] # => -1
请注意,当 other_array
大于 self
时,其尾随元素不会影响结果
[0, 1, 2] <=> [0, 1, 2, -3] # => -1 [0, 1, 2] <=> [0, 1, 2, 0] # => -1 [0, 1, 2] <=> [0, 1, 2, 3] # => -1
相关:请参阅 比较方法。
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); }
返回是否同时满足以下条件
-
self
和other_array
的大小相同。 -
它们的相应元素相同;也就是说,对于
(0...self.size)
中的每个索引i
,self[i] == other_array[i]
。
示例
[:foo, 'bar', 2] == [:foo, 'bar', 2] # => true [:foo, 'bar', 2] == [:foo, 'bar', 2.0] # => true [:foo, 'bar', 2] == [:foo, 'bar'] # => false # Different sizes. [:foo, 'bar', 2] == [:foo, 'bar', 3] # => false # Different elements.
此方法与方法 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
。
简而言之
a = [:foo, 'bar', 2] # Single argument index: returns one element. a[0] # => :foo # Zero-based index. a[-1] # => 2 # Negative index counts backwards from end. # Arguments start and length: returns an array. a[1, 2] # => ["bar", 2] a[-2, 2] # => ["bar", 2] # Negative start counts backwards from end. # Single argument range: returns an array. a[0..1] # => [:foo, "bar"] a[0..-2] # => [:foo, "bar"] # Negative range-begin counts backwards from end. a[-2..2] # => ["bar", 2] # Negative range-end counts backwards from end.
当给定单个整数参数 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
的新 Array
,其中包含从偏移量 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
,则返回一个新的空 Array
。
如果 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
,则返回一个新的空 Array
。
如果 range.end
为负,则从末尾计算结束索引
a = [:foo, 'bar', 2] a[0..-1] # => [:foo, "bar", 2] a[0..-2] # => [:foo, "bar"] a[0..-3] # => [:foo]
如果 range.start
为负,则从末尾计算起始索引
a = [:foo, 'bar', 2] a[-1..2] # => [2] a[-2..2] # => ["bar", 2] a[-3..2] # => [:foo, "bar", 2]
如果 range.start
大于数组大小,则返回 nil
。
a = [:foo, 'bar', 2] a[4..1] # => nil a[4..0] # => nil a[4..-1] # => nil
当给定单个 Enumerator::ArithmeticSequence
参数 aseq
时,返回一个与序列生成的索引相对应的元素 Array
。
a = ['--', 'data1', '--', 'data2', '--', 'data3'] a[(1..).step(2)] # => ["data1", "data2", "data3"]
与使用范围切片不同,如果算术序列的开头或结尾大于数组大小,则抛出 RangeError
。
a = ['--', 'data1', '--', 'data2', '--', 'data3'] a[(1..11).step(2)] # RangeError (((1..11).step(2)) out of range) a[(7..).step(2)] # RangeError (((7..).step(2)) out of range)
如果给定的参数是单个参数,并且其类型不是列出的类型之一,则尝试将其转换为 Integer
,如果无法转换,则引发错误
a = [:foo, 'bar', 2] # Raises TypeError (no implicit conversion of Symbol into Integer): a[:foo]
相关:请参阅 获取方法。
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]); }
根据给定的 object
在 self
中分配元素;返回 object
。
简而言之
a_orig = [:foo, 'bar', 2] # With argument index. a = a_orig.dup a[0] = 'foo' # => "foo" a # => ["foo", "bar", 2] a = a_orig.dup a[7] = 'foo' # => "foo" a # => [:foo, "bar", 2, nil, nil, nil, nil, "foo"] # With arguments start and length. a = a_orig.dup a[0, 2] = 'foo' # => "foo" a # => ["foo", 2] a = a_orig.dup a[6, 50] = 'foo' # => "foo" a # => [:foo, "bar", 2, nil, nil, nil, "foo"] # With argument range. a = a_orig.dup a[0..1] = 'foo' # => "foo" a # => ["foo", 2] a = a_orig.dup a[6..50] = 'foo' # => "foo" a # => [:foo, "bar", 2, nil, nil, nil, "foo"]
当给定 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
不是 Array
时,删除从偏移量 start
开始的 length - 1
个元素,并在偏移量 start
处分配 object
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
扩展数组,在偏移量 start
处分配 object
,并忽略 length
a = [:foo, 'bar', 2] a[6, 50] = 'foo' # => "foo" a # => [:foo, "bar", 2, nil, nil, nil, "foo"]
如果 length
为零,则移动偏移量 start
和后面的元素,并在偏移量 start
处分配 object
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
不是 Array
时,从偏移量 start
处开始移除 length - 1
个元素,并在偏移量 start
处分配 object
。
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
,则用 nil
扩展数组,在偏移量 range.begin
处分配 object
,并忽略 length
。
a = [:foo, 'bar', 2] a[6..50] = 'foo' # => "foo" a # => [:foo, "bar", 2, nil, nil, nil, "foo"]
如果 range.end
为零,则移动偏移量 start
及其之后的元素,并在偏移量 start
处分配 object
。
a = [:foo, 'bar', 2] a[1..0] = 'foo' # => "foo" a # => [:foo, "foo", "bar", 2]
如果 range.end
为负数,则在偏移量 start
处分配 object
,保留其后的 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
的每个元素是否都满足给定条件。
如果没有代码块且没有参数,则返回 self
的每个元素是否都是真值。
[[], {}, '', 0, 0.0, Object.new].all? # => true # All truthy objects. [[], {}, '', 0, 0.0, nil].all? # => false # nil is not truthy. [[], {}, '', 0, 0.0, false].all? # => false # false is not truthy.
如果给定参数 object
,则返回 self
中的每个元素 ele
是否满足 object === ele
。
[0, 0, 0].all?(0) # => true [0, 1, 2].all?(1) # => false ['food', 'fool', 'foot'].all?(/foo/) # => true ['food', 'drink'].all?(/foo/) # => false
如果给定代码块,则对 self
中的每个元素调用该代码块;返回该代码块是否只返回真值。
[0, 1, 2].all? { |ele| ele < 3 } # => true [0, 1, 2].all? { |ele| ele < 2 } # => false
如果同时给定代码块和参数 object
,则忽略该代码块,并按上述方式使用 object
。
特殊情况:如果 self
为空,则返回 true
(无论给定任何参数或代码块)。
相关信息:请参阅 用于查询的方法。
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
的任何元素是否满足给定条件。
如果没有代码块且没有参数,则返回 self
的任何元素是否为真值。
[nil, false, []].any? # => true # Array object is truthy. [nil, false, {}].any? # => true # Hash object is truthy. [nil, false, ''].any? # => true # String object is truthy. [nil, false].any? # => false # Nil and false are not truthy.
如果给定参数 object
,则返回 self
中的任何元素 ele
是否满足 object === ele
。
[nil, false, 0].any?(0) # => true [nil, false, 1].any?(0) # => false [nil, false, 'food'].any?(/foo/) # => true [nil, false, 'food'].any?(/bar/) # => false
如果给定代码块,则对 self
中的每个元素调用该代码块;返回该代码块是否返回任何真值。
[0, 1, 2].any? {|ele| ele < 1 } # => true [0, 1, 2].any? {|ele| ele < 0 } # => false
如果同时给定代码块和参数 object
,则忽略该代码块,并按上述方式使用 object
。
特殊情况:如果 self
为空,则返回 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] # => [:foo, "bar", 2] a.push(:baz, :bat) # => [:foo, "bar", 2, :baz, :bat]
即使参数是另一个数组,也会将每个参数作为单个元素追加。
a = [:foo, 'bar', 2] # => [:foo, "bar", 2] a.push([:baz, :bat], [:bam, :bad]) # => [:foo, "bar", 2, [:baz, :bat], [:bam, :bad]]
相关:请参阅 赋值方法。
返回 self
中第一个 ele
,使得 ele
是一个数组且 ele[0] == object
。
a = [{foo: 0}, [2, 4], [4, 5, 6], [4, 5]] a.assoc(4) # => [4, 5, 6]
如果未找到此类元素,则返回 nil
。
相关信息: Array#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; }
返回由给定 index
指定的 self
的元素;如果不存在此类元素,则返回 nil
;index
必须是 可转换为整数的对象。
对于非负数 index
,返回偏移量 index
处的 self
的元素。
a = [:foo, 'bar', 2] a.at(0) # => :foo a.at(2) # => 2 a.at(2.0) # => 2
对于负数 index
,则从 self
的末尾向后计数。
a.at(-2) # => "bar"
VALUE rb_ary_at(VALUE ary, VALUE pos) { return rb_ary_entry(ary, NUM2LONG(pos)); }
返回通过二分查找从 self
中找到的元素的整数索引,如果搜索没有找到合适的元素,则返回 nil
。
请参阅 二分查找。
相关:请参阅 获取方法。
static VALUE rb_ary_bsearch_index(VALUE ary) { long low = 0, high = RARRAY_LEN(ary), mid; int smaller = 0, satisfied = 0; VALUE v, val; RETURN_ENUMERATOR(ary, 0, 0); while (low < high) { mid = low + ((high - low) / 2); val = rb_ary_entry(ary, mid); v = rb_yield(val); if (FIXNUM_P(v)) { if (v == INT2FIX(0)) return INT2FIX(mid); smaller = (SIGNED_VALUE)v < 0; /* Fixnum preserves its sign-bit */ } else if (v == Qtrue) { satisfied = 1; smaller = 1; } else if (!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
中删除所有元素;返回 self
。
a = [:foo, 'bar', 2] a.clear # => []
相关信息:请参阅 用于删除的方法。
VALUE rb_ary_clear(VALUE ary) { rb_ary_modify_check(ary); if (ARY_SHARED_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
。
static VALUE rb_ary_collect(VALUE ary) { long i; VALUE collect; RETURN_SIZED_ENUMERATOR(ary, 0, 0, ary_enum_length); collect = rb_ary_new2(RARRAY_LEN(ary)); for (i = 0; i < RARRAY_LEN(ary); i++) { rb_ary_push(collect, rb_yield(RARRAY_AREF(ary, i))); } return collect; }
如果给定代码块,则对 self
的每个元素调用该代码块,并将该元素替换为代码块的返回值;返回 self
。
a = [:foo, 'bar', 2] a.map! { |element| element.class } # => [Symbol, String, Integer]
如果没有给定代码块,则返回一个新的 Enumerator
。
static VALUE rb_ary_collect_bang(VALUE ary) { long i; RETURN_SIZED_ENUMERATOR(ary, 0, 0, ary_enum_length); rb_ary_modify(ary); for (i = 0; i < RARRAY_LEN(ary); i++) { rb_ary_store(ary, i, rb_yield(RARRAY_AREF(ary, i))); } return ary; }
当给定一个代码块和一个正 可转换为整数的对象 参数 count
(0 < count <= self.size
) 时,将调用代码块,参数为大小为 count
的 self
的每个组合;返回 self
。
a = %w[a b c] # => ["a", "b", "c"] a.combination(2) {|combination| p combination } # => ["a", "b", "c"]
输出
["a", "b"] ["a", "c"] ["b", "c"]
不保证生成的组合的顺序。
当 count
为零时,将用新的空数组调用代码块一次。
a.combination(0) {|combination| p combination } [].combination(0) {|combination| p combination }
输出
[] []
当 count
为负数或大于 self.size
且 self
为非空时,不会调用代码块。
a.combination(-1) {|combination| fail 'Cannot happen' } # => ["a", "b", "c"] a.combination(4) {|combination| fail 'Cannot happen' } # => ["a", "b", "c"]
如果没有给定代码块,则返回一个新的 Enumerator
。
相关信息: Array#permutation
;另请参阅 用于迭代的方法。
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, false, nil, '', nil, [], nil, {}] a.compact # => [0, false, "", [], {}]
相关信息: Array#compact!
;另请参阅 用于删除的方法。
static VALUE rb_ary_compact(VALUE ary) { ary = rb_ary_dup(ary); rb_ary_compact_bang(ary); return ary; }
从 self
中删除所有 nil
元素;如果删除了任何元素,则返回 self
;否则返回 nil
。
a = [nil, 0, nil, false, nil, '', nil, [], nil, {}] a.compact! # => [0, false, "", [], {}] a # => [0, false, "", [], {}] a.compact! # => nil
相关信息: Array#compact
;另请参阅 用于删除的方法。
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
中每个数组中的所有元素添加到 self
;返回 self
。
a = [0, 1] a.concat(['two', 'three'], [:four, :five], a) # => [0, 1, "two", "three", :four, :five, 0, 1]
相关:请参阅 赋值方法。
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, :one, 'two', 3, 3.0].count # => 5
如果给定参数 object
,则返回与 object
==
的元素的计数。
[0, :one, 'two', 3, 3.0].count(3) # => 2
如果没有参数且给定代码块,则对每个元素调用代码块;返回代码块返回真值的元素的计数。
[0, 1, 2, 3].count {|element| element > 1 } # => 2
如果给定参数 object
和代码块,则会发出警告,忽略该代码块,并返回与 object
==
的元素的计数。
相关信息:请参阅 用于查询的方法。
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); }
如果给定代码块,则可能会调用该代码块,具体取决于参数 count
的值;count
必须是 可转换为整数的对象,或者为 nil
。
当 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
当 count
为 nil
时,将永远循环。
# Prints 0 and 1 forever. [0, 1].cycle {|element| puts element } [0, 1].cycle(nil) {|element| puts element }
如果没有给定代码块,则返回一个新的 Enumerator
。
相关信息:请参阅 用于迭代的方法。
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 == object
;返回最后一个删除的元素。
a = [0, 1, 2, 2.0] a.delete(2) # => 2.0 a # => [0, 1]
如果没有删除任何元素,则返回 nil
。
a.delete(2) # => nil
如果给定代码块,则从 self
中删除每个元素 ele
,使得 ele == object
。
如果找到任何此类元素,则忽略该代码块并返回最后一个删除的元素。
a = [0, 1, 2, 2.0] a.delete(2) {|element| fail 'Cannot happen' } # => 2.0 a # => [0, 1]
如果没有找到此类元素,则返回代码块的返回值。
a.delete(2) {|element| "Element #{element} not found." } # => "Element 2 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; }
删除 self
中给定 index
处的元素,该 index
必须是 可转换为整数的对象。
当 index
为非负数时,删除偏移量 index
处的元素。
a = [:foo, 'bar', 2] a.delete_at(1) # => "bar" a # => [:foo, 2]
当 index
为负数时,从数组末尾向后计数。
a = [:foo, 'bar', 2] a.delete_at(-2) # => "bar" a # => [:foo, 2]
当 index
超出范围时,返回 nil
。
a = [:foo, 'bar', 2] a.delete_at(3) # => nil a.delete_at(-4) # => 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
。
相关信息:请参阅 用于删除的方法。
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] [0, 1, 2].difference # => [0, 1, 2]
如果没有给出任何参数,则返回 self
的副本。
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 方法。
示例
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
中除了前 count
个元素之外的所有元素,其中 count
是一个非负整数;不会修改 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] a.drop(9) # => []
相关:请参阅 获取方法。
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
的每个连续元素调用该代码块;如果代码块返回 false
或 nil
,则停止;返回一个新数组,其中省略了代码块返回真值的那些元素;不会修改 self
。
a = [0, 1, 2, 3, 4, 5] a.drop_while {|element| element < 3 } # => [3, 4, 5]
如果没有给定代码块,则返回一个新的 Enumerator
。
相关:请参阅 获取方法。
static VALUE rb_ary_drop_while(VALUE ary) { long i; RETURN_ENUMERATOR(ary, 0, 0); for (i = 0; i < RARRAY_LEN(ary); i++) { if (!RTEST(rb_yield(RARRAY_AREF(ary, i)))) break; } return rb_ary_drop(ary, LONG2FIX(i)); }
如果给定了代码块,则迭代 self
的元素,并将每个元素传递给代码块;返回 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
。
相关信息:请参阅 用于迭代的方法。
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
的元素,并将每个数组索引传递给代码块;返回 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 } a # => []
输出
0 1
如果没有给定代码块,则返回一个新的 Enumerator
。
相关信息:请参阅 用于迭代的方法。
static VALUE rb_ary_each_index(VALUE ary) { long i; RETURN_SIZED_ENUMERATOR(ary, 0, 0, ary_enum_length); for (i=0; i<RARRAY_LEN(ary); i++) { rb_yield(LONG2NUM(i)); } return ary; }
如果 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
在范围内,则返回 self
中偏移量为 index
的元素;index
必须是可转换为整数的对象。
如果只给出单个参数 index
且没有代码块,则返回偏移量为 index
的元素。
a = [:foo, 'bar', 2] a.fetch(1) # => "bar" a.fetch(1.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" a.fetch(3, :foo) # => :foo
如果给出参数 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
中偏移量由 indexes
指定的元素。每个 indexes
都必须是可转换为整数的对象。
a = [:foo, :bar, :baz] a.fetch_values(2, 0) # => [:baz, :foo] a.fetch_values(2.1, 0) # => [:baz, :foo] a.fetch_values # => []
对于负索引,从数组末尾向后计数。
a.fetch_values(-2, -1) # [:bar, :baz]
如果没有给出代码块,如果任何索引超出范围,则引发异常。
如果给出了代码块,对于每个索引:
-
如果索引在范围内,则使用
self
的元素(如上所述)。 -
否则,使用索引调用代码块并使用代码块的返回值。
示例
a = [:foo, :bar, :baz] a.fetch_values(1, 0, 42, 777) { |index| index.to_s } # => [:bar, :foo, "42", "777"]
相关:请参阅 获取方法。
# File ruby_3_4_1/array.rb, line 210 def fetch_values(*indexes, &block) indexes.map! { |i| fetch(i, &block) } indexes end
替换 self
中的选定元素;可能会向 self
添加元素;始终返回 self
(永远不是新数组)。
简而言之
# Non-negative start. ['a', 'b', 'c', 'd'].fill('-', 1, 2) # => ["a", "-", "-", "d"] ['a', 'b', 'c', 'd'].fill(1, 2) {|e| e.to_s } # => ["a", "1", "2", "d"] # Extends with specified values if necessary. ['a', 'b', 'c', 'd'].fill('-', 3, 2) # => ["a", "b", "c", "-", "-"] ['a', 'b', 'c', 'd'].fill(3, 2) {|e| e.to_s } # => ["a", "b", "c", "3", "4"] # Fills with nils if necessary. ['a', 'b', 'c', 'd'].fill('-', 6, 2) # => ["a", "b", "c", "d", nil, nil, "-", "-"] ['a', 'b', 'c', 'd'].fill(6, 2) {|e| e.to_s } # => ["a", "b", "c", "d", nil, nil, "6", "7"] # For negative start, counts backwards from the end. ['a', 'b', 'c', 'd'].fill('-', -3, 3) # => ["a", "-", "-", "-"] ['a', 'b', 'c', 'd'].fill(-3, 3) {|e| e.to_s } # => ["a", "1", "2", "3"] # Range. ['a', 'b', 'c', 'd'].fill('-', 1..2) # => ["a", "-", "-", "d"] ['a', 'b', 'c', 'd'].fill(1..2) {|e| e.to_s } # => ["a", "1", "2", "d"]
当给出参数 start
和 count
时,它们选择要替换的 self
的元素;每个参数都必须是可转换为整数的对象(或 nil
)。
-
start
指定要替换的第一个元素的从零开始的偏移量;nil
表示零。 -
count
是要替换的连续元素数量;nil
表示“其余全部”。
如果给出参数 object
,则使用该对象进行所有替换。
o = Object.new # => #<Object:0x0000014e7bff7600> a = ['a', 'b', 'c', 'd'] # => ["a", "b", "c", "d"] a.fill(o, 1, 2) # => ["a", #<Object:0x0000014e7bff7600>, #<Object:0x0000014e7bff7600>, "d"]
如果给出了代码块,则为每个要替换的元素调用一次代码块;传递给代码块的值是要替换元素的索引(而不是元素本身);代码块的返回值替换该元素。
a = ['a', 'b', 'c', 'd'] # => ["a", "b", "c", "d"] a.fill(1, 2) {|element| element.to_s } # => ["a", "1", "2", "d"]
对于参数 start
和 count
:
-
如果
start
为非负数,则替换从偏移量start
开始的count
个元素。['a', 'b', 'c', 'd'].fill('-', 0, 2) # => ["-", "-", "c", "d"] ['a', 'b', 'c', 'd'].fill('-', 1, 2) # => ["a", "-", "-", "d"] ['a', 'b', 'c', 'd'].fill('-', 2, 2) # => ["a", "b", "-", "-"] ['a', 'b', 'c', 'd'].fill(0, 2) {|e| e.to_s } # => ["0", "1", "c", "d"] ['a', 'b', 'c', 'd'].fill(1, 2) {|e| e.to_s } # => ["a", "1", "2", "d"] ['a', 'b', 'c', 'd'].fill(2, 2) {|e| e.to_s } # => ["a", "b", "2", "3"]
如果需要,则扩展
self
。['a', 'b', 'c', 'd'].fill('-', 3, 2) # => ["a", "b", "c", "-", "-"] ['a', 'b', 'c', 'd'].fill('-', 4, 2) # => ["a", "b", "c", "d", "-", "-"] ['a', 'b', 'c', 'd'].fill(3, 2) {|e| e.to_s } # => ["a", "b", "c", "3", "4"] ['a', 'b', 'c', 'd'].fill(4, 2) {|e| e.to_s } # => ["a", "b", "c", "d", "4", "5"]
如果需要,则用
nil
填充。['a', 'b', 'c', 'd'].fill('-', 5, 2) # => ["a", "b", "c", "d", nil, "-", "-"] ['a', 'b', 'c', 'd'].fill('-', 6, 2) # => ["a", "b", "c", "d", nil, nil, "-", "-"] ['a', 'b', 'c', 'd'].fill(5, 2) {|e| e.to_s } # => ["a", "b", "c", "d", nil, "5", "6"] ['a', 'b', 'c', 'd'].fill(6, 2) {|e| e.to_s } # => ["a", "b", "c", "d", nil, nil, "6", "7"]
如果
count
为非正数,则不执行任何操作。['a', 'b', 'c', 'd'].fill('-', 2, 0) # => ["a", "b", "c", "d"] ['a', 'b', 'c', 'd'].fill('-', 2, -100) # => ["a", "b", "c", "d"] ['a', 'b', 'c', 'd'].fill('-', 6, -100) # => ["a", "b", "c", "d"] ['a', 'b', 'c', 'd'].fill(2, 0) {|e| fail 'Cannot happen' } # => ["a", "b", "c", "d"] ['a', 'b', 'c', 'd'].fill(2, -100) {|e| fail 'Cannot happen' } # => ["a", "b", "c", "d"] ['a', 'b', 'c', 'd'].fill(6, -100) {|e| fail 'Cannot happen' } # => ["a", "b", "c", "d"]
-
如果
start
为负数,则从self
的末尾向后计数。['a', 'b', 'c', 'd'].fill('-', -4, 3) # => ["-", "-", "-", "d"] ['a', 'b', 'c', 'd'].fill('-', -3, 3) # => ["a", "-", "-", "-"] ['a', 'b', 'c', 'd'].fill(-4, 3) {|e| e.to_s } # => ["0", "1", "2", "d"] ['a', 'b', 'c', 'd'].fill(-3, 3) {|e| e.to_s } # => ["a", "1", "2", "3"]
如果需要,则扩展
self
。['a', 'b', 'c', 'd'].fill('-', -2, 3) # => ["a", "b", "-", "-", "-"] ['a', 'b', 'c', 'd'].fill('-', -1, 3) # => ["a", "b", "c", "-", "-", "-"] ['a', 'b', 'c', 'd'].fill(-2, 3) {|e| e.to_s } # => ["a", "b", "2", "3", "4"] ['a', 'b', 'c', 'd'].fill(-1, 3) {|e| e.to_s } # => ["a", "b", "c", "3", "4", "5"]
如果
start
为负数且超出范围,则从self
的开头开始。['a', 'b', 'c', 'd'].fill('-', -5, 2) # => ["-", "-", "c", "d"] ['a', 'b', 'c', 'd'].fill('-', -6, 2) # => ["-", "-", "c", "d"] ['a', 'b', 'c', 'd'].fill(-5, 2) {|e| e.to_s } # => ["0", "1", "c", "d"] ['a', 'b', 'c', 'd'].fill(-6, 2) {|e| e.to_s } # => ["0", "1", "c", "d"]
如果
count
为非正数,则不执行任何操作。['a', 'b', 'c', 'd'].fill('-', -2, 0) # => ["a", "b", "c", "d"] ['a', 'b', 'c', 'd'].fill('-', -2, -1) # => ["a", "b", "c", "d"] ['a', 'b', 'c', 'd'].fill(-2, 0) {|e| fail 'Cannot happen' } # => ["a", "b", "c", "d"] ['a', 'b', 'c', 'd'].fill(-2, -1) {|e| fail 'Cannot happen' } # => ["a", "b", "c", "d"]
当给出参数 range
时,它必须是一个 Range
对象,其成员为数值;它的 begin
和 end
值确定要替换的 self
的元素。
-
如果
begin
和end
均为正数,则它们指定要替换的第一个和最后一个元素。['a', 'b', 'c', 'd'].fill('-', 1..2) # => ["a", "-", "-", "d"] ['a', 'b', 'c', 'd'].fill(1..2) {|e| e.to_s } # => ["a", "1", "2", "d"]
如果
end
小于begin
,则不替换任何元素。['a', 'b', 'c', 'd'].fill('-', 2..1) # => ["a", "b", "c", "d"] ['a', 'b', 'c', 'd'].fill(2..1) {|e| e.to_s } # => ["a", "b", "c", "d"]
-
如果其中一个为负数(或两者均为负数),则从
self
的末尾向后计数。['a', 'b', 'c', 'd'].fill('-', -3..2) # => ["a", "-", "-", "d"] ['a', 'b', 'c', 'd'].fill('-', 1..-2) # => ["a", "-", "-", "d"] ['a', 'b', 'c', 'd'].fill('-', -3..-2) # => ["a", "-", "-", "d"] ['a', 'b', 'c', 'd'].fill(-3..2) {|e| e.to_s } # => ["a", "1", "2", "d"] ['a', 'b', 'c', 'd'].fill(1..-2) {|e| e.to_s } # => ["a", "1", "2", "d"] ['a', 'b', 'c', 'd'].fill(-3..-2) {|e| e.to_s } # => ["a", "1", "2", "d"]
-
如果排除了
end
值(请参阅Range#exclude_end?
),则省略最后一个替换。['a', 'b', 'c', 'd'].fill('-', 1...2) # => ["a", "-", "c", "d"] ['a', 'b', 'c', 'd'].fill('-', 1...-2) # => ["a", "-", "c", "d"] ['a', 'b', 'c', 'd'].fill(1...2) {|e| e.to_s } # => ["a", "1", "c", "d"] ['a', 'b', 'c', 'd'].fill(1...-2) {|e| e.to_s } # => ["a", "1", "c", "d"]
-
如果范围是无限的(请参阅 无限范围),则替换到
self
末尾的元素。['a', 'b', 'c', 'd'].fill('-', 1..) # => ["a", "-", "-", "-"] ['a', 'b', 'c', 'd'].fill(1..) {|e| e.to_s } # => ["a", "1", "2", "3"]
-
如果范围是无始的(请参阅 无始范围),则替换从
self
开头的元素。['a', 'b', 'c', 'd'].fill('-', ..2) # => ["-", "-", "-", "d"] ['a', 'b', 'c', 'd'].fill(..2) {|e| e.to_s } # => ["0", "1", "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] a.select {|element| element.to_s.start_with?('b') } # => ["bar", :bam]
如果没有给定代码块,则返回一个新的 Enumerator
。
相关:请参阅 获取方法。
如果给定了代码块,则对 self
的每个元素调用该代码块;从 self
中删除代码块返回 false
或 nil
的那些元素。
如果删除了任何元素,则返回 self
。
a = [:foo, 'bar', 2, :bam] a.select! {|element| element.to_s.start_with?('b') } # => ["bar", :bam]
如果未删除任何元素,则返回 nil
。
如果没有给定代码块,则返回一个新的 Enumerator
。
相关信息:请参阅 用于删除的方法。
返回指定元素的从零开始的整数索引,或 nil
。
如果只给出参数 object
,则返回第一个元素 element
的索引,其中 object == element
。
a = [:foo, 'bar', 2, 'bar'] a.index('bar') # => 1
如果没有找到此类元素,则返回 nil
。
如果只给出一个代码块,则对每个连续元素调用代码块;返回代码块返回真值的第一个元素的索引。
a = [:foo, 'bar', 2, 'bar'] a.index {|element| element == 'bar' } # => 1
如果代码块从未返回真值,则返回 nil
。
如果没有给出参数或代码块,则返回一个新的 Enumerator
。
相关信息:请参阅 用于查询的方法。
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
返回元素,或 nil
;不会修改 self
。
如果没有给出参数,则返回第一个元素(如果可用)。
a = [:foo, 'bar', 2] a.first # => :foo a # => [:foo, "bar", 2]
如果 self
为空,则返回 nil
。
[].first # => nil
如果给出了非负整数参数 count
,则在一个新数组中返回前 count
个元素(如果可用)。
a.first(0) # => [] a.first(2) # => [:foo, "bar"] a.first(50) # => [:foo, "bar", 2]
相关信息:请参阅 用于查询的方法。
# File ruby_3_4_1/array.rb, line 129 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
的递归扁平化,递归深度为 depth
层;depth
必须是可转换为整数的对象或 nil
。在每个递归级别:
-
每个是数组的元素都将被“扁平化”(即,替换为其单独的数组元素)。
-
每个不是数组的元素都保持不变(即使该元素是具有实例方法
flatten
的对象)。
如果给出非负整数参数 depth
,则递归地扁平化 depth
层。
a = [ 0, [ 1, [2, 3], 4 ], 5, {foo: 0}, Set.new([6, 7]) ] a # => [0, [1, [2, 3], 4], 5, {:foo=>0}, #<Set: {6, 7}>] a.flatten(0) # => [0, [1, [2, 3], 4], 5, {:foo=>0}, #<Set: {6, 7}>] a.flatten(1 ) # => [0, 1, [2, 3], 4, 5, {:foo=>0}, #<Set: {6, 7}>] a.flatten(1.1) # => [0, 1, [2, 3], 4, 5, {:foo=>0}, #<Set: {6, 7}>] a.flatten(2) # => [0, 1, 2, 3, 4, 5, {:foo=>0}, #<Set: {6, 7}>] a.flatten(3) # => [0, 1, 2, 3, 4, 5, {:foo=>0}, #<Set: {6, 7}>]
如果给出 nil
或负数 depth
,则扁平化所有层。
a.flatten # => [0, 1, 2, 3, 4, 5, {:foo=>0}, #<Set: {6, 7}>] a.flatten(-1) # => [0, 1, 2, 3, 4, 5, {:foo=>0}, #<Set: {6, 7}>]
相关:Array#flatten!
;另请参阅转换方法。
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
的递归扁平化返回,递归深度为 depth
层;depth
必须是可转换为整数的对象,或 nil
。在每个递归级别:
-
每个是数组的元素都将被“扁平化”(即,替换为其单独的数组元素)。
-
每个不是数组的元素都保持不变(即使该元素是具有实例方法
flatten
的对象)。
如果没有扁平化任何元素,则返回 nil
。
如果给出非负整数参数 depth
,则递归地扁平化 depth
层。
a = [ 0, [ 1, [2, 3], 4 ], 5, {foo: 0}, Set.new([6, 7]) ] a # => [0, [1, [2, 3], 4], 5, {:foo=>0}, #<Set: {6, 7}>] a.dup.flatten!(1) # => [0, 1, [2, 3], 4, 5, {:foo=>0}, #<Set: {6, 7}>] a.dup.flatten!(1.1) # => [0, 1, [2, 3], 4, 5, {:foo=>0}, #<Set: {6, 7}>] a.dup.flatten!(2) # => [0, 1, 2, 3, 4, 5, {:foo=>0}, #<Set: {6, 7}>] a.dup.flatten!(3) # => [0, 1, 2, 3, 4, 5, {:foo=>0}, #<Set: {6, 7}>]
如果给出 nil
或负数参数 depth
,则扁平化所有层。
a.dup.flatten! # => [0, 1, 2, 3, 4, 5, {:foo=>0}, #<Set: {6, 7}>] a.dup.flatten!(-1) # => [0, 1, 2, 3, 4, 5, {:foo=>0}, #<Set: {6, 7}>]
相关:Array#flatten
;另请参阅赋值方法。
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_ary_freeze(result); rb_ary_replace(ary, result); if (mod) ARY_SET_EMBED_LEN(result, 0); return ary; }
冻结 self
(如果尚未冻结);返回 self
。
a = [] a.frozen? # => false a.freeze a.frozen? # => true
不得对 self
进行任何进一步的更改;如果尝试更改,则引发 FrozenError
。
相关:Kernel#frozen?
。
VALUE rb_ary_freeze(VALUE ary) { RUBY_ASSERT(RB_TYPE_P(ary, T_ARRAY)); if (OBJ_FROZEN(ary)) return ary; if (!ARY_EMBED_P(ary) && !ARY_SHARED_P(ary) && !ARY_SHARED_ROOT_P(ary)) { ary_shrink_capa(ary); } return rb_obj_freeze(ary); }
返回 self
的整数哈希值。
具有相同内容的两个数组将具有相同的哈希值(并且将使用 eql? 进行比较)。
['a', 'b'].hash == ['a', 'b'].hash # => true ['a', 'b'].hash == ['a', 'c'].hash # => false ['a', 'b'].hash == ['a'].hash # => false
static VALUE rb_ary_hash(VALUE ary) { return rb_ary_hash_values(RARRAY_LEN(ary), RARRAY_CONST_PTR(ary)); }
返回 self
中是否存在某个元素 element
,使得 object == element
[0, 1, 2].include?(2) # => true [0, 1, 2].include?(2.0) # => true [0, 1, 2].include?(2.1) # => 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; }
返回指定元素的从零开始的整数索引,或 nil
。
如果只给出参数 object
,则返回第一个元素 element
的索引,其中 object == element
。
a = [:foo, 'bar', 2, 'bar'] a.index('bar') # => 1
如果没有找到此类元素,则返回 nil
。
如果只给出一个代码块,则对每个连续元素调用代码块;返回代码块返回真值的第一个元素的索引。
a = [:foo, 'bar', 2, 'bar'] a.index {|element| element == 'bar' } # => 1
如果代码块从未返回真值,则返回 nil
。
如果没有给出参数或代码块,则返回一个新的 Enumerator
。
相关信息:请参阅 用于查询的方法。
将 self
的元素替换为 other_array
的元素,other_array
必须是 可转换为数组的对象;返回 self
a = ['a', 'b', 'c'] # => ["a", "b", "c"] a.replace(['d', 'e']) # => ["d", "e"]
相关:请参阅 赋值方法。
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)) { RUBY_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_buffer(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; }
将给定的 objects
作为 self
的元素插入;返回 self
。
当 index
为非负数时,将 objects
插入到偏移量为 index
的元素之前
a = ['a', 'b', 'c'] # => ["a", "b", "c"] a.insert(1, :x, :y, :z) # => ["a", :x, :y, :z, "b", "c"]
如果 index
超出数组范围 (index >= self.size
),则扩展数组
a = ['a', 'b', 'c'] # => ["a", "b", "c"] a.insert(5, :x, :y, :z) # => ["a", "b", "c", nil, nil, :x, :y, :z]
当 index
为负数时,将 objects
插入到偏移量为 index + self.size
的元素之后
a = ['a', 'b', 'c'] # => ["a", "b", "c"] a.insert(-2, :x, :y, :z) # => ["a", "b", :x, :y, :z, "c"]
如果没有给出 objects
,则不执行任何操作
a = ['a', 'b', 'c'] # => ["a", "b", "c"] a.insert(1) # => ["a", "b", "c"] a.insert(50) # => ["a", "b", "c"] a.insert(-50) # => ["a", "b", "c"]
如果给出了 objects
并且 index
为负数且超出范围,则引发 IndexError
错误。
相关:请参阅 赋值方法。
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
形成的新字符串
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_array
是否至少有一个元素与 self
的某个元素 #eql?
[1, 2, 3].intersect?([3, 4, 5]) # => true [1, 2, 3].intersect?([4, 5, 6]) # => false
每个元素必须正确实现方法 #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?
的每个元素;重复元素被省略
[0, 0, 1, 1, 2, 3].intersection([0, 1, 2], [0, 1, 3]) # => [0, 1]
每个元素必须正确实现方法 #hash
。
保留来自 self
的顺序
[0, 1, 2].intersection([2, 1, 0]) # => [0, 1, 2]
如果没有给出任何参数,则返回 self
的副本。
相关:请参阅 组合方法。
static VALUE rb_ary_intersection_multi(int argc, VALUE *argv, VALUE ary) { VALUE result = rb_ary_dup(ary); int i; for (i = 0; i < argc; i++) { result = rb_ary_and(result, argv[i]); } return result; }
返回通过连接 self
的转换元素形成的新字符串;对于每个元素 element
-
如果
element
是kind_of?(Array)
,则使用element.join(separator)
递归转换。 -
否则,使用
element.to_s
进行转换。
如果没有给出参数,则使用输出字段分隔符 $,
进行连接
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
的每个元素调用该块;如果该块没有返回真值,则从 self
中删除该元素
a = [:foo, 'bar', 2, :bam] a.keep_if {|element| element.to_s.start_with?('b') } # => ["bar", :bam]
如果没有给定代码块,则返回一个新的 Enumerator
。
相关信息:请参阅 用于删除的方法。
static VALUE rb_ary_keep_if(VALUE ary) { RETURN_SIZED_ENUMERATOR(ary, 0, 0, ary_enum_length); rb_ary_select_bang(ary); return ary; }
从 self
返回元素,或者 nil
;self
不会被修改。
如果没有给出参数,则返回最后一个元素,如果 self
为空,则返回 nil
a = [:foo, 'bar', 2] a.last # => 2 a # => [:foo, "bar", 2] [].last # => nil
如果给出了非负整数参数 count
,则返回一个新数组,其中包含 self
的尾部 count
个元素(如果可用)
a = [:foo, 'bar', 2] a.last(2) # => ["bar", 2] a.last(50) # => [:foo, "bar", 2] a.last(0) # => [] [].last(3) # => []
相关:请参阅 获取方法。
# File ruby_3_4_1/array.rb, line 166 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
中元素的计数
[0, 1, 2].length # => 3 [].length # => 0
相关信息:请参阅 用于查询的方法。
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
。
如果给定代码块,则对 self
的每个元素调用该代码块,并将该元素替换为代码块的返回值;返回 self
。
a = [:foo, 'bar', 2] a.map! { |element| element.class } # => [Symbol, String, Integer]
如果没有给定代码块,则返回一个新的 Enumerator
。
返回以下之一
-
来自
self
的最大值元素。 -
来自
self
的最大值元素的新数组。
不修改 self
。
如果没有给出块,则 self
中的每个元素必须使用数字响应方法 #<=>
。
如果没有参数且没有块,则返回根据方法 #<=>
具有最大值的 self
中的元素
[1, 0, 3, 2].max # => 3
如果给出了非负数值参数 count
且没有块,则返回一个新数组,该数组最多包含 count
个元素,并按照方法 #<=>
降序排列
[1, 0, 3, 2].max(3) # => [3, 2, 1] [1, 0, 3, 2].max(3.0) # => [3, 2, 1] [1, 0, 3, 2].max(9) # => [3, 2, 1, 0] [1, 0, 3, 2].max(0) # => []
如果给出了块,则该块必须返回一个数字。
如果给出了块且没有参数,则调用该块 self.size - 1
次以比较元素;返回根据该块具有最大值的元素
['0', '', '000', '00'].max {|a, b| a.size <=> b.size } # => "000"
如果给出了非负数值参数 count
且有一个块,则返回一个新数组,该数组最多包含 count
个元素,并根据该块降序排列
['0', '', '000', '00'].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
。
如果没有给出块,则 self
中的每个元素必须使用数字响应方法 #<=>
。
如果没有参数且没有块,则返回根据方法 #<=>
具有最小值的 self
中的元素
[1, 0, 3, 2].min # => 0
如果给出了非负数值参数 count
且没有块,则返回一个新数组,该数组最多包含 count
个元素,并按照方法 #<=>
升序排列
[1, 0, 3, 2].min(3) # => [0, 1, 2] [1, 0, 3, 2].min(3.0) # => [0, 1, 2] [1, 0, 3, 2].min(9) # => [0, 1, 2, 3] [1, 0, 3, 2].min(0) # => []
如果给出了块,则该块必须返回一个数字。
如果给出了块且没有参数,则调用该块 self.size - 1
次以比较元素;返回根据该块具有最小值的元素
['0', '', '000', '00'].min {|a, b| a.size <=> b.size } # => ""
如果给出了非负数值参数 count
且有一个块,则返回一个新数组,该数组最多包含 count
个元素,并根据该块升序排列
['0', '', '000', '00'].min(2) {|a, b| a.size <=> b.size } # => ["", "0"]
相关:请参阅 获取方法。
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
的最小值和最大值元素的 2 个元素的数组;不修改 self
。
如果没有给出块,则使用方法 #<=>
确定最小值和最大值
[1, 0, 3, 2].minmax # => [0, 3]
如果给出了块,则该块必须返回一个数字;调用该块 self.size - 1
次以比较元素;返回根据该块具有最小值和最大值的元素
['0', '', '000', '00'].minmax {|a, b| a.size <=> b.size } # => ["", "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
,否则返回 false
。
如果没有给出块并且没有参数,则如果 self
没有真值元素,则返回 true
,否则返回 false
[nil, false].none? # => true [nil, 0, false].none? # => false [].none? # => true
如果给出了参数 object
,则如果对于任何元素 element
, object === element
,则返回 false
;否则返回 true
['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
如果给出了块,则对 self
中的每个元素调用该块;如果该块没有返回真值,则返回 true
,否则返回 false
[0, 1, 2].none? {|element| element > 3 } # => true [0, 1, 2].none? {|element| element > 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
如果给出了参数 object
,则如果对于只有一个元素 element
, object === element
,则返回 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_4_1/pack.rb, line 7 def pack(fmt, buffer: nil) Primitive.pack_pack(fmt, buffer) end
迭代 self
元素的排列;排列的顺序是不确定的。
如果给出了块和一个范围内的正整数参数 count
(0 < count <= self.size
),则对大小为 count
的 self
的每个排列调用该块;返回 self
a = [0, 1, 2] perms = [] a.permutation(1) {|perm| perms.push(perm) } perms # => [[0], [1], [2]] perms = [] a.permutation(2) {|perm| perms.push(perm) } perms # => [[0, 1], [0, 2], [1, 0], [1, 2], [2, 0], [2, 1]] perms = [] a.permutation(3) {|perm| perms.push(perm) } perms # => [[0, 1, 2], [0, 2, 1], [1, 0, 2], [1, 2, 0], [2, 0, 1], [2, 1, 0]]
当 count
为零时,将用新的空数组调用代码块一次。
perms = [] a.permutation(0) {|perm| perms.push(perm) } perms # => [[]]
当 count
超出范围(负数或大于 self.size
)时,不会调用该块
a.permutation(-1) {|permutation| fail 'Cannot happen' } a.permutation(4) {|permutation| fail 'Cannot happen' }
如果没有给定代码块,则返回一个新的 Enumerator
。
相关:迭代方法。
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
的尾部元素。
如果没有给出参数,则删除并返回最后一个元素(如果可用);否则返回 nil
a = [:foo, 'bar', 2] a.pop # => 2 a # => [:foo, "bar"] [].pop # => nil
如果给出了非负整数参数 count
,则返回一个新数组,其中包含 self
的尾部 count
个元素(如果可用)
a = [:foo, 'bar', 2] a.pop(2) # => ["bar", 2] a # => [:foo] a = [:foo, 'bar', 2] a.pop(50) # => [:foo, "bar", 2] a # => []
相关:Array#push
;另请参阅 用于删除的方法。
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]
相关:Array#shift
;另请参阅 用于赋值的方法。
计算所有数组(包括 self
和 other_arrays
)中元素的组合。
-
组合的数量是所有数组(包括
self
和other_arrays
)大小的乘积。 -
返回的组合顺序是不确定的。
如果没有给出块,则返回作为数组的数组的组合。
p = [0, 1].product([2, 3]) # => [[0, 2], [0, 3], [1, 2], [1, 3]] p.size # => 4 p = [0, 1].product([2, 3], [4, 5]) # => [[0, 2, 4], [0, 2, 5], [0, 3, 4], [0, 3, 5], [1, 2, 4], [1, 2, 5], [1, 3, 4], [1, 3,... p.size # => 8
如果 self
或任何参数为空,则返回一个空数组。
[].product([2, 3], [4, 5]) # => [] [0, 1].product([2, 3], []) # => []
如果没有给出参数,则返回一个包含 1 个元素数组的数组,每个数组包含 self
的一个元素。
a.product # => [[0], [1], [2]]
如果给出了块,则用每个组合调用该块;返回 self
。
p = [] [0, 1].product([2, 3]) {|combination| p.push(combination) } p # => [[0, 2], [0, 3], [1, 2], [1, 3]]
如果 self
或任何参数为空,则不调用该块。
[].product([2, 3], [4, 5]) {|combination| fail 'Cannot happen' } # => [] [0, 1].product([2, 3], []) {|combination| fail 'Cannot happen' } # => [0, 1]
如果没有给出参数,则使用 self
的每个元素作为 1 个元素的数组来调用该块。
p = [] [0, 1].product {|combination| p.push(combination) } p # => [[0], [1]]
相关:请参阅 组合方法。
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] # => [:foo, "bar", 2] a.push(:baz, :bat) # => [:foo, "bar", 2, :baz, :bat]
即使参数是另一个数组,也会将每个参数作为单个元素追加。
a = [:foo, 'bar', 2] # => [:foo, "bar", 2] a.push([:baz, :bat], [:bam, :bad]) # => [: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
中第一个元素 ele
,使得 ele
是一个数组且 ele[1] == object
。
a = [{foo: 0}, [2, 4], [4, 5, 6], [4, 5]] a.rassoc(4) # => [2, 4] a.rassoc(5) # => [4, 5, 6]
如果未找到此类元素,则返回 nil
。
相关:Array#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
。
相关:用于获取的方法。
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
的每个元素调用该块;删除每个使该块返回真值的元素。
如果删除了任何元素,则返回 self
。
a = [:foo, 'bar', 2, 'bat'] a.reject! {|element| element.to_s.start_with?('b') } # => [:foo, 2]
如果没有删除元素,则返回 nil
。
如果没有给定代码块,则返回一个新的 Enumerator
。
相关信息:请参阅 用于删除的方法。
static VALUE rb_ary_reject_bang(VALUE ary) { RETURN_SIZED_ENUMERATOR(ary, 0, 0, ary_enum_length); rb_ary_modify(ary); return ary_reject_bang(ary); }
如果给出了块,则使用 self
元素的长度为 size
的每个重复组合调用该块;每个组合都是一个数组;返回 self
。组合的顺序是不确定的。
如果给出了一个正整数参数 size
,则使用 self
元素的每个 size
元组重复组合调用该块。组合的数量是 (size+1)(size+2)/2
。
示例
-
size
为 1c = [] [0, 1, 2].repeated_combination(1) {|combination| c.push(combination) } c # => [[0], [1], [2]]
-
size
为 2c = [] [0, 1, 2].repeated_combination(2) {|combination| c.push(combination) } c # => [[0, 0], [0, 1], [0, 2], [1, 1], [1, 2], [2, 2]]
如果 size
为零,则使用一个空数组调用该块一次。
如果 size
为负数,则不调用该块。
[0, 1, 2].repeated_combination(-1) {|combination| fail 'Cannot happen' }
如果没有给定代码块,则返回一个新的 Enumerator
。
相关:请参阅 组合方法。
static VALUE rb_ary_repeated_combination(VALUE ary, VALUE num) { long n, i, len; n = NUM2LONG(num); /* Combination size from argument */ RETURN_SIZED_ENUMERATOR(ary, 1, &num, rb_ary_repeated_combination_size); /* Return enumerator if no block */ len = RARRAY_LEN(ary); if (n < 0) { /* yield nothing */ } else if (n == 0) { rb_yield(rb_ary_new2(0)); } else if (n == 1) { for (i = 0; i < RARRAY_LEN(ary); i++) { rb_yield(rb_ary_new3(1, RARRAY_AREF(ary, i))); } } else if (len == 0) { /* yield nothing */ } else { volatile VALUE t0; long *p = ALLOCV_N(long, t0, n); VALUE ary0 = ary_make_shared_copy(ary); /* private defensive copy of ary */ RBASIC_CLEAR_CLASS(ary0); rcombinate0(len, n, p, n, ary0); /* compute and yield repeated combinations */ ALLOCV_END(t0); RBASIC_SET_CLASS_RAW(ary0, rb_cArray); } return ary; }
如果给出了块,则使用 self
元素的长度为 size
的每个重复排列调用该块;每个排列都是一个数组;返回 self
。排列的顺序是不确定的。
如果给出了一个正整数参数 size
,则使用 self
元素的每个 size
元组重复排列调用该块。排列的数量是 self.size**size
。
示例
-
size
为 1p = [] [0, 1, 2].repeated_permutation(1) {|permutation| p.push(permutation) } p # => [[0], [1], [2]]
-
size
为 2p = [] [0, 1, 2].repeated_permutation(2) {|permutation| p.push(permutation) } p # => [[0, 0], [0, 1], [0, 2], [1, 0], [1, 1], [1, 2], [2, 0], [2, 1], [2, 2]]
如果 size
为零,则使用一个空数组调用该块一次。
如果 size
为负数,则不调用该块。
[0, 1, 2].repeated_permutation(-1) {|permutation| fail 'Cannot happen' }
如果没有给定代码块,则返回一个新的 Enumerator
。
相关:请参阅 组合方法。
static VALUE rb_ary_repeated_permutation(VALUE ary, VALUE num) { long r, n, i; n = RARRAY_LEN(ary); /* Array length */ RETURN_SIZED_ENUMERATOR(ary, 1, &num, rb_ary_repeated_permutation_size); /* Return Enumerator if no block */ r = NUM2LONG(num); /* Permutation size from argument */ if (r < 0) { /* no permutations: yield nothing */ } else if (r == 0) { /* exactly one permutation: the zero-length array */ rb_yield(rb_ary_new2(0)); } else if (r == 1) { /* this is a special, easy case */ for (i = 0; i < RARRAY_LEN(ary); i++) { rb_yield(rb_ary_new3(1, RARRAY_AREF(ary, i))); } } else { /* this is the general case */ volatile VALUE t0; long *p = ALLOCV_N(long, t0, r); VALUE ary0 = ary_make_shared_copy(ary); /* private defensive copy of ary */ RBASIC_CLEAR_CLASS(ary0); rpermute0(n, r, p, ary0); /* compute and yield repeated permutations */ ALLOCV_END(t0); RBASIC_SET_CLASS_RAW(ary0, rb_cArray); } return ary; }
将 self
的元素替换为 other_array
的元素,other_array
必须是 可转换为数组的对象;返回 self
a = ['a', 'b', 'c'] # => ["a", "b", "c"] a.replace(['d', 'e']) # => ["d", "e"]
相关:请参阅 赋值方法。
返回一个新数组,其中包含 self
的元素,顺序相反。
[0, 1, 2].reverse # => [2, 1, 0]
相关:请参阅 组合方法。
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
元素的顺序;返回 self
。
a = [0, 1, 2] a.reverse! # => [2, 1, 0] a # => [2, 1, 0]
相关:请参阅 赋值方法。
static VALUE rb_ary_reverse_bang(VALUE ary) { return rb_ary_reverse(ary); }
当给出一个块时,以相反的顺序遍历 self
的元素,并将每个元素按相反的顺序传递给该块;返回 self
。
a = [] [0, 1, 2].reverse_each {|element| a.push(element) } a # => [2, 1, 0]
允许在迭代期间修改数组。
a = ['a', 'b', 'c'] a.reverse_each {|element| a.clear if element.start_with?('b') } a # => []
当没有给出块时,返回一个新的 Enumerator
。
相关信息:请参阅 用于迭代的方法。
static VALUE rb_ary_reverse_each(VALUE ary) { long len; RETURN_SIZED_ENUMERATOR(ary, 0, 0, ary_enum_length); len = RARRAY_LEN(ary); while (len--) { long nlen; rb_yield(RARRAY_AREF(ary, len)); nlen = RARRAY_LEN(ary); if (nlen < len) { len = nlen; } } return ary; }
返回 object == element
的最后一个元素的索引。
如果给出了参数 object
,则返回找到的最后一个此类元素的索引。
a = [:foo, 'bar', 2, 'bar'] a.rindex('bar') # => 3
如果未找到此类对象,则返回 nil
。
如果给出了块,则使用每个连续的元素调用该块;返回该块返回真值的最后一个元素的索引。
a = [:foo, 'bar', 2, 'bar'] a.rindex {|element| element == 'bar' } # => 3
如果代码块从未返回真值,则返回 nil
。
当既没有给出参数也没有给出块时,返回一个新的 Enumerator
。
相关信息:请参阅 用于查询的方法。
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
形成的新的数组,其中的元素从一端旋转到另一端。
对于非负数值 count
,将元素从开头旋转到结尾。
[0, 1, 2, 3].rotate(2) # => [2, 3, 0, 1] [0, 1, 2, 3].rotate(2.1) # => [2, 3, 0, 1]
如果 count
很大,则使用 count % array.size
作为计数。
[0, 1, 2, 3].rotate(22) # => [2, 3, 0, 1]
如果 count
为零,则不旋转任何元素。
[0, 1, 2, 3].rotate(0) # => [0, 1, 2, 3]
对于负数值 count
,从结尾到开头按相反方向旋转。
[0, 1, 2, 3].rotate(-1) # => [3, 0, 1, 2]
如果 count
很小(远离零),则使用 count % array.size
作为计数。
[0, 1, 2, 3].rotate(-21) # => [3, 0, 1, 2]
相关:请参阅 获取方法。
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
。
对于非负数值 count
,将 count
个元素从开头旋转到结尾。
[0, 1, 2, 3].rotate!(2) # => [2, 3, 0, 1] [0, 1, 2, 3].rotate!(2.1) # => [2, 3, 0, 1]
如果 count
很大,则使用 count % array.size
作为计数。
[0, 1, 2, 3].rotate!(21) # => [1, 2, 3, 0]
如果 count
为零,则不旋转任何元素。
[0, 1, 2, 3].rotate!(0) # => [0, 1, 2, 3]
对于负数值 count
,从结尾到开头按相反方向旋转。
[0, 1, 2, 3].rotate!(-1) # => [3, 0, 1, 2]
如果 count
很小(远离零),则使用 count % array.size
作为计数。
[0, 1, 2, 3].rotate!(-21) # => [3, 0, 1, 2]
相关:请参阅 赋值方法。
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
中的随机元素,由关键字参数 random
给出的对象选择。
如果没有给出参数 count
,则返回 self
中的一个随机元素。
a = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] a.sample # => 3 a.sample # => 8
如果 self
为空,则返回 nil
。
[].sample # => nil
如果给出了非负数值参数 count
,则返回一个新数组,其中包含 self
中的 count
个随机元素。
a.sample(3) # => [8, 9, 2] a.sample(6) # => [9, 6, 0, 3, 1, 4]
结果数组的顺序与 self
的顺序无关。
如果 self
为空,则返回一个新的空 Array
。
[].sample(4) # => []
可能会在 self
中返回重复项。
a = [1, 1, 1, 2, 2, 3] a.sample(a.size) # => [1, 1, 3, 2, 1, 2]
返回的元素不超过 a.size
个(因为没有引入新的重复项)。
a.sample(50) # => [6, 4, 1, 8, 5, 9, 0, 2, 3, 7]
使用关键字参数 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_4_1/array.rb, line 95 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] a.select {|element| element.to_s.start_with?('b') } # => ["bar", :bam]
如果没有给定代码块,则返回一个新的 Enumerator
。
相关:请参阅 获取方法。
static VALUE rb_ary_select(VALUE ary) { VALUE result; long i; RETURN_SIZED_ENUMERATOR(ary, 0, 0, ary_enum_length); result = rb_ary_new2(RARRAY_LEN(ary)); for (i = 0; i < RARRAY_LEN(ary); i++) { if (RTEST(rb_yield(RARRAY_AREF(ary, i)))) { rb_ary_push(result, rb_ary_elt(ary, i)); } } return result; }
如果给定了代码块,则对 self
的每个元素调用该代码块;从 self
中删除代码块返回 false
或 nil
的那些元素。
如果删除了任何元素,则返回 self
。
a = [:foo, 'bar', 2, :bam] a.select! {|element| element.to_s.start_with?('b') } # => ["bar", :bam]
如果未删除任何元素,则返回 nil
。
如果没有给定代码块,则返回一个新的 Enumerator
。
相关信息:请参阅 用于删除的方法。
static VALUE rb_ary_select_bang(VALUE ary) { struct select_bang_arg args; RETURN_SIZED_ENUMERATOR(ary, 0, 0, ary_enum_length); rb_ary_modify(ary); args.ary = ary; args.len[0] = args.len[1] = 0; return rb_ensure(select_bang_i, (VALUE)&args, select_bang_ensure, (VALUE)&args); }
从 self
中删除并返回前导元素。
如果没有参数,则删除并返回一个元素(如果有),否则返回 nil
。
a = [0, 1, 2, 3] a.shift # => 0 a # => [1, 2, 3] [].shift # => nil
如果给出了非负数值参数 count
,则删除并返回前 count
个元素。
a = [0, 1, 2, 3] a.shift(2) # => [0, 1] a # => [2, 3] a.shift(1.1) # => [2] a # => [3] a.shift(0) # => [] a # => [3]
如果 count
很大,则删除并返回所有元素。
a = [0, 1, 2, 3] a.shift(50) # => [0, 1, 2, 3] a # => []
如果 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
中的所有元素,顺序随机,由关键字参数 random
给出的对象选择。
a = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] a.shuffle # => [0, 8, 1, 9, 6, 3, 4, 7, 2, 5] a.shuffle # => [8, 9, 0, 5, 1, 2, 6, 4, 7, 3]
包含重复元素。
a = [0, 1, 0, 1, 0, 1, 0, 1, 0, 1] a.shuffle # => [1, 0, 1, 1, 0, 0, 1, 0, 0, 1] a.shuffle # => [1, 1, 0, 0, 0, 1, 1, 0, 0, 1]
使用关键字参数 random
给出的对象作为随机数生成器。
相关:请参阅 获取方法。
# File ruby_3_4_1/array.rb, line 45 def shuffle(random: Random) Primitive.rb_ary_shuffle(random) end
将 self
中的所有元素随机打乱,由关键字参数 random
给出的对象选择。返回 self
。
a = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] a.shuffle! # => [5, 3, 8, 7, 6, 1, 9, 4, 2, 0] a.shuffle! # => [9, 4, 0, 6, 2, 8, 1, 5, 3, 7]
包含重复元素。
a = [0, 1, 0, 1, 0, 1, 0, 1, 0, 1] a.shuffle! # => [1, 0, 0, 1, 1, 0, 1, 0, 0, 1] a.shuffle! # => [0, 1, 0, 1, 1, 0, 1, 0, 1, 0]
使用关键字参数 random
给出的对象作为随机数生成器。
相关:请参阅 赋值方法。
# File ruby_3_4_1/array.rb, line 22 def shuffle!(random: Random) Primitive.rb_ary_shuffle_bang(random) end
从 self
返回元素;不修改 self
。
简而言之
a = [:foo, 'bar', 2] # Single argument index: returns one element. a[0] # => :foo # Zero-based index. a[-1] # => 2 # Negative index counts backwards from end. # Arguments start and length: returns an array. a[1, 2] # => ["bar", 2] a[-2, 2] # => ["bar", 2] # Negative start counts backwards from end. # Single argument range: returns an array. a[0..1] # => [:foo, "bar"] a[0..-2] # => [:foo, "bar"] # Negative range-begin counts backwards from end. a[-2..2] # => ["bar", 2] # Negative range-end counts backwards from end.
当给定单个整数参数 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
的新 Array
,其中包含从偏移量 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
,则返回一个新的空 Array
。
如果 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
,则返回一个新的空 Array
。
如果 range.end
为负,则从末尾计算结束索引
a = [:foo, 'bar', 2] a[0..-1] # => [:foo, "bar", 2] a[0..-2] # => [:foo, "bar"] a[0..-3] # => [:foo]
如果 range.start
为负,则从末尾计算起始索引
a = [:foo, 'bar', 2] a[-1..2] # => [2] a[-2..2] # => ["bar", 2] a[-3..2] # => [:foo, "bar", 2]
如果 range.start
大于数组大小,则返回 nil
。
a = [:foo, 'bar', 2] a[4..1] # => nil a[4..0] # => nil a[4..-1] # => nil
当给定单个 Enumerator::ArithmeticSequence
参数 aseq
时,返回一个与序列生成的索引相对应的元素 Array
。
a = ['--', 'data1', '--', 'data2', '--', 'data3'] a[(1..).step(2)] # => ["data1", "data2", "data3"]
与使用范围切片不同,如果算术序列的开头或结尾大于数组大小,则抛出 RangeError
。
a = ['--', 'data1', '--', 'data2', '--', 'data3'] a[(1..11).step(2)] # RangeError (((1..11).step(2)) out of range) a[(7..).step(2)] # RangeError (((7..).step(2)) out of range)
如果给定的参数是单个参数,并且其类型不是列出的类型之一,则尝试将其转换为 Integer
,如果无法转换,则引发错误
a = [:foo, 'bar', 2] # Raises TypeError (no implicit conversion of Symbol into Integer): a[:foo]
相关:请参阅 获取方法。
从 self
中删除并返回元素。
如果给出了数值参数 index
,则删除并返回偏移量 index
处的元素。
a = ['a', 'b', 'c', 'd'] a.slice!(2) # => "c" a # => ["a", "b", "d"] a.slice!(2.1) # => "d" a # => ["a", "b"]
如果 index
为负,则从 self
的末尾向后计数
a = ['a', 'b', 'c', 'd'] a.slice!(-2) # => "c" a # => ["a", "b", "d"]
如果 index
超出范围,则返回 nil
。
如果给出了数值参数 start
和 length
,则从零开始的偏移量 start
开始删除 self
中的 length
个元素;在新数组中返回已删除的对象。
a = ['a', 'b', 'c', 'd'] a.slice!(1, 2) # => ["b", "c"] a # => ["a", "d"] a.slice!(0.1, 1.1) # => ["a"] a # => ["d"]
如果 start
为负数,则从 self
的末尾向后计数。
a = ['a', 'b', 'c', 'd'] a.slice!(-2, 1) # => ["c"] a # => ["a", "b", "d"]
如果 start
超出范围,则返回 nil
。
a = ['a', 'b', 'c', 'd'] a.slice!(5, 1) # => nil a.slice!(-5, 1) # => nil
如果 start + length
超过数组大小,则删除并返回从偏移量 start
到末尾的所有元素。
a = ['a', 'b', 'c', 'd'] a.slice!(2, 50) # => ["c", "d"] a # => ["a", "b"]
如果 start == a.size
并且 length
为非负数,则返回一个新的空数组。
如果 length
为负数,则返回 nil
。
如果给出了 Range
参数 range
,则将 range.min
视为 start
(如上),将 range.size
视为 length
(如上)。
a = ['a', 'b', 'c', 'd'] a.slice!(1..2) # => ["b", "c"] a # => ["a", "d"]
如果 range.start == a.size
,则返回一个新的空数组。
a = ['a', 'b', 'c', 'd'] a.slice!(4..5) # => []
如果 range.start
大于数组大小,则返回 nil
。
a = ['a', 'b', 'c', 'd'] a.slice!(5..6) # => nil
如果 range.start
为负数,则通过从 self
的末尾向后计数来计算起始索引。
a = ['a', 'b', 'c', 'd'] a.slice!(-2..2) # => ["c"]
如果 range.end
为负数,则通过从 self
的末尾向后计数来计算结束索引。
a = ['a', 'b', 'c', 'd'] a.slice!(0..-2) # => ["a", "b", "c"]
相关信息:请参阅 用于删除的方法。
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
的元素,并已排序。
如果没有给出块,则使用运算符 #<=>
比较元素(请参阅 Object#<=>)。
[0, 2, 3, 1].sort # => [0, 1, 2, 3]
如果给出了块,则使用 self
中的每对元素组合调用该块;对于每一对 a
和 b
,该块应返回一个数值。
-
当
b
在a
之后时,返回负数。 -
当
a
和b
等效时,返回零。 -
当
a
在b
之后时,返回正数。
示例
a = [3, 2, 0, 1] a.sort {|a, b| a <=> b } # => [0, 1, 2, 3] a.sort {|a, b| b <=> a } # => [3, 2, 1, 0]
当该块返回零时,a
和 b
的顺序是不确定的,并且可能不稳定。
相关:请参阅 获取方法。
VALUE rb_ary_sort(VALUE ary) { ary = rb_ary_dup(ary); rb_ary_sort_bang(ary); return ary; }
类似于 Array#sort
,但返回 self
,其元素就地排序。
相关:请参阅 赋值方法。
VALUE rb_ary_sort_bang(VALUE ary) { rb_ary_modify(ary); RUBY_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); } if (ARY_EMBED_LEN(tmp) > ARY_CAPA(ary)) { ary_resize_capa(ary, ARY_EMBED_LEN(tmp)); } 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 { RUBY_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
。
相关:请参阅 赋值方法。
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; }
如果没有给出代码块,则返回 init
和 self
所有元素的总和;对于数组 array
和值 init
,等效于
sum = init array.each {|element| sum += element } sum
例如,[e0, e1, e2].sum
返回 init + e0 + e1 + e2
。
示例
[0, 1, 2, 3].sum # => 6 [0, 1, 2, 3].sum(100) # => 106 ['abc', 'def', 'ghi'].sum('jkl') # => "jklabcdefghi" [[:foo, :bar], ['foo', 'bar']].sum([2, 3]) # => [2, 3, :foo, :bar, "foo", "bar"]
init
值和元素不需要是数字,但必须都与 +
兼容。
# Raises TypeError: Array can't be coerced into Integer. [[:foo, :bar], ['foo', 'bar']].sum(2)
如果给定了代码块,则使用 self
的每个元素调用代码块;代码块的返回值(而不是元素本身)被用作加数。
['zero', 1, :two].sum('Coerced and concatenated: ') {|element| element.to_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
的前 count
个元素(如果可用);count
必须是非负数;不会修改 self
。
a = ['a', 'b', 'c', 'd'] a.take(2) # => ["a", "b"] a.take(2.1) # => ["a", "b"] a.take(50) # => ["a", "b", "c", "d"] a.take(0) # => []
相关:请参阅 获取方法。
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
的每个连续元素调用代码块;如果代码块返回 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.take_while {|element| false } # => []
如果没有给定代码块,则返回一个新的 Enumerator
。
不修改 self
。
相关:请参阅 获取方法。
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
。
否则,返回一个包含 self
元素的新数组。
class MyArray < Array; end my_a = MyArray.new(['foo', 'bar', 'two']) a = my_a.to_a a # => ["foo", "bar", "two"] a.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; }
返回由 self
形成的新哈希。
如果没有给出代码块,则 self
的每个元素必须是包含 2 个元素的子数组;将每个子数组在新哈希中形成键值对。
a = [['foo', 'zero'], ['bar', 'one'], ['baz', 'two']] a.to_h # => {"foo"=>"zero", "bar"=>"one", "baz"=>"two"} [].to_h # => {}
如果给出了代码块,则代码块必须返回一个包含 2 个元素的数组;使用 self
的每个元素调用代码块;将每个返回的数组在返回的哈希中形成键值对。
a = ['foo', :bar, 1, [2, 3], {baz: 4}] a.to_h {|element| [element, element.class] } # => {"foo"=>String, :bar=>Symbol, 1=>Integer, [2, 3]=>Array, {:baz=>4}=>Hash}
相关:请参阅 用于转换的方法。
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
形成的新字符串
a = [:foo, 'bar', 2] a.inspect # => "[:foo, \"bar\", 2]"
相关:请参阅 用于转换的方法。
返回一个新数组,它是 self
的转置矩阵。
a = [[:a0, :a1], [:b0, :b1], [:c0, :c1]] a.transpose # => [[:a0, :b0, :c0], [:a1, :b1, :c1]]
self
的元素必须全部大小相同。
相关:请参阅 用于转换的方法。
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]
保留顺序(保留第一个找到的项的位置)。
[3, 2, 1, 0].union([5, 3], [4, 2]) # => [3, 2, 1, 0, 5, 4]
如果没有给出参数,则返回 self
的副本。
相关:请参阅 组合方法。
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?
比较元素,识别并删除元素。
a = [0, 0, 1, 1, 2, 2] a.uniq! # => [0, 1, 2] a.uniq! # => nil
如果给出了代码块,则为每个元素调用代码块;使用方法 eql?
比较代码块返回值来识别和忽略“重复”元素;也就是说,如果一个元素的代码块返回值与前一个元素的代码块返回值相同,则该元素是重复的。
a = ['a', 'aa', 'aaa', 'b', 'bb', 'bbb'] a.uniq! {|element| element.size } # => ["a", "aa", "aaa"] a.uniq! {|element| element.size } # => 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)) { 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]
相关:Array#shift
;另请参阅 用于赋值的方法。
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
中的元素;不会修改 self
。
返回的数组中包含的对象是 self
中由给定的 specifiers
选择的元素,其中每个 specifiers
必须是数值索引或 Range
。
简而言之
a = ['a', 'b', 'c', 'd'] # Index specifiers. a.values_at(2, 0, 2, 0) # => ["c", "a", "c", "a"] # May repeat. a.values_at(-4, -3, -2, -1) # => ["a", "b", "c", "d"] # Counts backwards if negative. a.values_at(-50, 50) # => [nil, nil] # Outside of self. # Range specifiers. a.values_at(1..3) # => ["b", "c", "d"] # From range.begin to range.end. a.values_at(1...3) # => ["b", "c"] # End excluded. a.values_at(3..1) # => [] # No such elements. a.values_at(-3..3) # => ["b", "c", "d"] # Negative range.begin counts backwards. a.values_at(-50..3) # Raises RangeError. a.values_at(1..-2) # => ["b", "c"] # Negative range.end counts backwards. a.values_at(1..-50) # => [] # No such elements. # Mixture of specifiers. a.values_at(2..3, 3, 0..1, 0) # => ["c", "d", "d", "a", "b", "a"]
如果没有给出 specifiers
,则返回一个新的空数组。
a = ['a', 'b', 'c', 'd'] a.values_at # => []
对于每个数值 index
,包含一个元素。
-
对于每个范围内的非负数值
index
(小于self.size
),包含偏移量为index
的元素。a.values_at(0, 2) # => ["a", "c"] a.values_at(0.1, 2.9) # => ["a", "c"]
-
对于每个范围内的负数值
index
(大于或等于- self.size
),从self
的末尾向后计数。a.values_at(-1, -4) # => ["d", "a"]
给定的索引可以按任意顺序排列,并且可以重复。
a.values_at(2, 0, 1, 0, 2) # => ["c", "a", "b", "a", "c"]
对于每个超出范围的 index
,包含 nil
。
a.values_at(4, -5) # => [nil, nil]
对于每个 Range
指定符 range
,根据 range.begin
和 range.end
包含元素。
-
如果
range.begin
和range.end
都是非负数并且在范围内(小于self.size
),则包含从索引range.begin
到range.end - 1
(如果range.exclude_end?
为真),或到range.end
(否则) 的元素。a.values_at(1..2) # => ["b", "c"] a.values_at(1...2) # => ["b"]
-
如果
range.begin
是负数且在范围内(大于或等于- self.size
),则从self
的末尾向后计数。a.values_at(-2..3) # => ["c", "d"]
-
如果
range.begin
是负数且超出范围,则引发异常。a.values_at(-5..3) # Raises RangeError.
-
如果
range.end
是正数且超出范围,则使用nil
元素扩展返回的数组。a.values_at(1..5) # => ["b", "c", "d", nil, nil]
-
如果
range.end
是负数且在范围内,则从self
的末尾向后计数。a.values_at(1..-2) # => ["b", "c"]
-
如果
range.end
是负数且超出范围,则返回空数组。a.values_at(1..-5) # => []
给定的范围可以按任意顺序排列,并且可以重复。
a.values_at(2..3, 0..1, 2..3) # => ["c", "d", "a", "b", "c", "d"]
给定的指定符可以是索引和范围的任意混合。
a.values_at(3, 1..2, 0, 2..3) # => ["d", "b", "c", "a", "c", "d"]
相关:请参阅 获取方法。
static VALUE rb_ary_values_at(int argc, VALUE *argv, VALUE ary) { long i, olen = RARRAY_LEN(ary); VALUE result = rb_ary_new_capa(argc); for (i = 0; i < argc; ++i) { append_values_at_single(result, ary, olen, argv[i]); } RB_GC_GUARD(ary); return result; }
如果没有给出代码块,则将 self
与 other_arrays
的集合组合;返回一个由子数组组成的新数组。
[0, 1].zip(['zero', 'one'], [:zero, :one]) # => [[0, "zero", :zero], [1, "one", :one]]
返回的
-
外部数组的大小为
self.size
。 -
每个子数组的大小为
other_arrays.size + 1
。 -
第 n 个子数组包含 (按顺序)
-
self
的第 n 个元素。 -
每个其他数组的第 n 个元素(如果可用)。
-
示例
a = [0, 1] zipped = a.zip(['zero', 'one'], [:zero, :one]) # => [[0, "zero", :zero], [1, "one", :one]] zipped.size # => 2 # Same size as a. zipped.first.size # => 3 # Size of other arrays plus 1.
当其他数组都与 self
的大小相同时,返回的子数组是重新排列,其中包含所有数组(包括 self
)的元素,没有遗漏或添加。
a = [:a0, :a1, :a2, :a3] b = [:b0, :b1, :b2, :b3] c = [:c0, :c1, :c2, :c3] d = a.zip(b, c) pp d # => [[:a0, :b0, :c0], [:a1, :b1, :c1], [:a2, :b2, :c2], [:a3, :b3, :c3]]
当其他数组之一比 self
小时,用 nil
元素填充相应的子数组。
a = [:a0, :a1, :a2, :a3] b = [:b0, :b1, :b2] c = [:c0, :c1] d = a.zip(b, c) pp d # => [[:a0, :b0, :c0], [:a1, :b1, :c1], [:a2, :b2, nil], [:a3, nil, nil]]
当其他数组之一比 self
大时,忽略其尾随元素。
a = [:a0, :a1, :a2, :a3] b = [:b0, :b1, :b2, :b3, :b4] c = [:c0, :c1, :c2, :c3, :c4, :c5] d = a.zip(b, c) pp d # => [[:a0, :b0, :c0], [:a1, :b1, :c1], [:a2, :b2, :c2], [:a3, :b3, :c3]]
如果给出了代码块,则使用每个其他数组调用该代码块;返回 nil
。
d = [] a = [:a0, :a1, :a2, :a3] b = [:b0, :b1, :b2, :b3] c = [:c0, :c1, :c2, :c3] a.zip(b, c) {|sub_array| d.push(sub_array.reverse) } # => nil pp d # => [[:c0, :b0, :a0], [:c1, :b1, :a1], [:c2, :b2, :a2], [:c3, :b3, :a3]]
对于 other_arrays 中实际上不是数组的对象,如果定义了,则将“其他数组”形成为 object.to_ary
,否则形成为 object.each.to_a
。
相关:请参阅 用于转换的方法。
static VALUE rb_ary_zip(int argc, VALUE *argv, VALUE ary) { int i, j; long len = RARRAY_LEN(ary); VALUE result = Qnil; for (i=0; i<argc; i++) { argv[i] = take_items(argv[i], len); } if (rb_block_given_p()) { int arity = rb_block_arity(); if (arity > 1) { VALUE work, *tmp; tmp = ALLOCV_N(VALUE, work, argc+1); for (i=0; i<RARRAY_LEN(ary); i++) { tmp[0] = RARRAY_AREF(ary, i); for (j=0; j<argc; j++) { tmp[j+1] = rb_ary_elt(argv[j], i); } rb_yield_values2(argc+1, tmp); } if (work) ALLOCV_END(work); } else { for (i=0; i<RARRAY_LEN(ary); i++) { VALUE tmp = rb_ary_new2(argc+1); rb_ary_push(tmp, RARRAY_AREF(ary, i)); for (j=0; j<argc; j++) { rb_ary_push(tmp, rb_ary_elt(argv[j], i)); } rb_yield(tmp); } } } else { result = rb_ary_new_capa(len); for (i=0; i<len; i++) { VALUE tmp = rb_ary_new_capa(argc+1); rb_ary_push(tmp, RARRAY_AREF(ary, i)); for (j=0; j<argc; j++) { rb_ary_push(tmp, rb_ary_elt(argv[j], i)); } rb_ary_push(result, tmp); } } return result; }
返回 self
和 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]
相关:请参阅 组合方法。
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); }