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