类 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", :%, :*]
-
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(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,它将对象转换为数组。
-
CSV::Table#to_a
-
Gem::List#to_a
-
Racc::ISet#to_a
-
Rinda::RingFinger#to_a
-
Ripper::Lexer::Elem#to_a
用法示例¶ ↑
除了它通过Enumerable模块混入的方法外,Array类还具有用于访问、搜索和以其他方式操作数组的专有方法。
下面说明了一些更常用的方法。
访问元素¶ ↑
可以使用 Array#[] 方法检索数组中的元素。它可以接受单个整数参数(数字索引)、一对参数(起始和长度)或一个范围。负索引从末尾开始计数,-1 是最后一个元素。
arr = [1, 2, 3, 4, 5, 6] arr[2] #=> 3 arr[100] #=> nil arr[-3] #=> 4 arr[2, 3] #=> [3, 4, 5] arr[1..4] #=> [2, 3, 4, 5] arr[1..-3] #=> [2, 3, 4]
访问特定数组元素的另一种方法是使用 at 方法
arr.at(0) #=> 1
要对数组边界之外的索引引发错误,或者在发生这种情况时提供默认值,您可以使用 fetch。
arr = ['a', 'b', 'c', 'd', 'e', 'f'] arr.fetch(100) #=> IndexError: index 100 outside of array bounds: -6...6 arr.fetch(100, "oops") #=> "oops"
特殊方法 first 和 last 将分别返回数组的第一个和最后一个元素。
arr.first #=> 1 arr.last #=> 6
要返回数组的第一个 n 个元素,请使用 take
arr.take(3) #=> [1, 2, 3]
drop 的作用与 take 相反,它会返回删除 n 个元素后的元素
arr.drop(3) #=> [4, 5, 6]
获取有关 Array 的信息¶ ↑
数组始终跟踪自身的长度。要查询数组中包含的元素数量,请使用 length、count 或 size。
browsers = ['Chrome', 'Firefox', 'Safari', 'Opera', 'IE'] browsers.length #=> 5 browsers.count #=> 5
要检查数组是否包含任何元素
browsers.empty? #=> false
要检查数组中是否包含特定项
browsers.include?('Konqueror') #=> false
向数组添加项¶ ↑
arr = [1, 2, 3, 4] arr.push(5) #=> [1, 2, 3, 4, 5] arr << 6 #=> [1, 2, 3, 4, 5, 6]
unshift 会将新项添加到数组的开头。
arr.unshift(0) #=> [0, 1, 2, 3, 4, 5, 6]
使用 insert,您可以将新元素添加到数组的任何位置。
arr.insert(3, 'apple') #=> [0, 1, 2, 'apple', 3, 4, 5, 6]
使用 insert 方法,您还可以一次插入多个值
arr.insert(3, 'orange', 'pear', 'grapefruit') #=> [0, 1, 2, "orange", "pear", "grapefruit", "apple", 3, 4, 5, 6]
从 Array 中移除项¶ ↑
方法 pop 会移除数组中的最后一个元素并返回它
arr = [1, 2, 3, 4, 5, 6] arr.pop #=> 6 arr #=> [1, 2, 3, 4, 5]
要检索并同时删除第一个项,请使用 shift
arr.shift #=> 1 arr #=> [2, 3, 4, 5]
要删除特定索引处的元素
arr.delete_at(2) #=> 4 arr #=> [2, 3, 5]
要删除数组中任何位置的特定元素,请使用 delete
arr = [1, 2, 2, 3] arr.delete(2) #=> 2 arr #=> [1,3]
如果您需要从数组中删除 nil 值,一个有用的方法是 compact
arr = ['foo', 0, nil, 'bar', 7, 'baz', nil] arr.compact #=> ['foo', 0, 'bar', 7, 'baz'] arr #=> ['foo', 0, nil, 'bar', 7, 'baz', nil] arr.compact! #=> ['foo', 0, 'bar', 7, 'baz'] arr #=> ['foo', 0, 'bar', 7, 'baz']
另一个常见的需求是从数组中删除重复元素。
arr = [2, 5, 6, 556, 6, 6, 8, 9, 0, 123, 556] arr.uniq #=> [2, 5, 6, 556, 8, 9, 0, 123]
遍历数组¶ ↑
像所有包含 Enumerable 模块的类一样,Array 都有一个 each 方法,该方法定义应该迭代哪些元素以及如何迭代。就 Array 的 each 而言,Array 实例中的所有元素都将按顺序传递给提供的块。
请注意,此操作不会更改数组。
arr = [1, 2, 3, 4, 5] arr.each {|a| print a -= 10, " "} # prints: -9 -8 -7 -6 -5 #=> [1, 2, 3, 4, 5]
另一个有时有用的迭代器是 reverse_each,它将按相反顺序遍历数组中的元素。
words = %w[first second third fourth fifth sixth] str = "" words.reverse_each {|word| str += "#{word} "} p str #=> "sixth fifth fourth third second first "
可以使用 map 方法基于原始数组创建一个新数组,但其值由提供的块修改
arr.map {|a| 2*a} #=> [2, 4, 6, 8, 10] arr #=> [1, 2, 3, 4, 5] arr.map! {|a| a**2} #=> [1, 4, 9, 16, 25] arr #=> [1, 4, 9, 16, 25]
从 Array 中选择项¶ ↑
可以根据块中定义的条件从数组中选择元素。选择可以以破坏性或非破坏性方式进行。虽然破坏性操作会修改它们被调用的数组,但非破坏性方法通常会返回一个包含选定元素的新数组,但保持原始数组不变。
非破坏性选择¶ ↑
arr = [1, 2, 3, 4, 5, 6] arr.select {|a| a > 3} #=> [4, 5, 6] arr.reject {|a| a < 3} #=> [3, 4, 5, 6] arr.drop_while {|a| a < 4} #=> [4, 5, 6] arr #=> [1, 2, 3, 4, 5, 6]
破坏性选择¶ ↑
select! 和 reject! 是与 select 和 reject 对应的破坏性方法
与 select 与 reject 类似,delete_if 和 keep_if 在提供相同的块时具有完全相反的结果
arr.delete_if {|a| a < 4} #=> [4, 5, 6] arr #=> [4, 5, 6] arr = [1, 2, 3, 4, 5, 6] arr.keep_if {|a| a < 4} #=> [1, 2, 3] arr #=> [1, 2, 3]
这里有什么¶ ↑
首先,其他地方有什么。类 Array
-
继承自 类 Object。
-
包含 模块 Enumerable,它提供了许多额外的的方法。
这里,类 Array 提供了以下有用的方法:
创建 Array 的方法¶ ↑
-
::[]: 返回一个用给定对象填充的新数组。 -
::new: 返回一个新数组。 -
::try_convert: 返回一个从给定对象创建的新数组。
另请参阅 创建数组。
查询方法¶ ↑
-
all?: 返回是否所有元素都满足给定条件。 -
any?: 返回是否有任何元素满足给定条件。 -
count: 返回满足给定条件的元素的计数。 -
empty?: 返回是否没有元素。 -
find_index(别名为index): 返回第一个满足给定条件的元素的索引。 -
hash: 返回整数哈希码。 -
include?: 返回是否有任何元素==给定对象。 -
none?: 返回是否没有元素==给定对象。 -
one?: 返回是否正好有一个元素==给定对象。 -
rindex: 返回最后一个满足给定条件的元素的索引。
比较方法¶ ↑
-
<=>: 返回 -1、0 或 1,取决于self小于、等于或大于给定对象。 -
==: 返回self中的每个元素是否==给定对象中的对应元素。 -
eql?: 返回self中的每个元素是否eql?给定对象中的对应元素。
获取方法¶ ↑
这些方法不会修改 self。
-
assoc: 返回第一个元素是数组且其第一个元素==给定对象的元素。 -
at: 返回给定偏移量处的元素。 -
bsearch: 返回通过二分查找根据给定块选择的元素。 -
bsearch_index: 返回通过二分查找根据给定块选择的元素的索引。 -
compact: 返回一个包含所有非nil元素的数组。 -
dig: 返回嵌套对象中由给定索引和其他参数指定的对象。 -
drop: 返回由给定索引确定的尾部元素。 -
drop_while: 返回由给定块确定的尾部元素。 -
fetch: 返回给定偏移量处的元素。 -
fetch_values: 返回给定偏移量处的元素。 -
first: 返回一个或多个前导元素。 -
last: 返回一个或多个尾部元素。 -
rassoc: 返回第一个元素是数组且其第二个元素==给定对象的元素。 -
reject: 返回一个包含未被给定块拒绝的元素的数组。 -
reverse: 返回所有元素,顺序颠倒。 -
rotate: 返回所有元素,某些元素从一端旋转到另一端。 -
sample: 返回一个或多个随机元素。 -
shuffle: 返回随机顺序的元素。 -
take: 返回由给定索引确定的前导元素。 -
take_while: 返回由给定块确定的前导元素。 -
uniq: 返回一个包含非重复元素的数组。 -
values_at: 返回给定偏移量处的元素。
赋值方法¶ ↑
这些方法在 self 中添加、替换或重新排序元素。
-
<<: 追加一个元素。 -
[]=: 使用给定对象赋值指定的元素。 -
concat: 从给定数组追加所有元素。 -
fill: 使用指定对象替换指定元素。 -
flatten!: 将self中的每个嵌套数组替换为该数组中的元素。 -
initialize_copy(别名为replace): 将self的内容替换为给定数组的内容。 -
insert: 在给定偏移量处插入给定对象;不替换元素。 -
reverse!: 用其反转的元素替换self。 -
rotate!: 用其旋转的元素替换self。 -
shuffle!: 用其随机顺序的元素替换self。 -
sort_by!: 用其排序的元素替换self,由给定块确定。
删除方法¶ ↑
这些方法都从 self 中删除元素
-
clear: 删除所有元素。 -
compact!: 删除所有nil元素。 -
delete: 删除等于给定对象的元素。 -
delete_at: 删除给定偏移量处的元素。 -
delete_if: 删除由给定块指定的元素。 -
keep_if: 删除未由给定块指定的元素。 -
pop: 删除并返回最后一个元素。 -
reject!: 删除由给定块指定的元素。 -
shift: 删除并返回第一个元素。 -
slice!: 删除并返回一系列元素。 -
uniq!: 删除重复项。
组合方法¶ ↑
-
&: 返回一个包含self和给定数组中都找到的元素的数组。 -
+: 返回一个包含self的所有元素,后跟给定数组的所有元素的数组。 -
-: 返回一个包含self中所有未在给定数组中找到的元素的数组。 -
|: 返回一个包含self的所有元素和给定数组的所有元素的数组,删除重复项。 -
difference: 返回一个包含self中所有未在任何给定数组中找到的元素的数组。 -
intersection: 返回一个包含self和每个给定数组中都找到的元素的数组。 -
product: 返回或生成self和给定数组中元素的所有组合。 -
reverse: 返回一个包含self的所有元素,顺序颠倒的数组。 -
union: 返回一个包含self的所有元素和给定数组的所有元素的数组,删除重复项。
迭代方法¶ ↑
-
combination: 使用self的元素组合调用给定块;组合不会多次使用同一元素。 -
cycle: 使用每个元素调用给定块,然后再次执行,指定次数或永远。 -
each: 将每个元素传递给给定块。 -
each_index: 将每个元素索引传递给给定块。 -
permutation: 使用self的元素排列调用给定块;排列不会多次使用同一元素。 -
repeated_combination: 使用self的元素组合调用给定块;组合可以多次使用同一元素。 -
repeated_permutation: 使用self元素的排列组合调用给定的代码块;排列组合中可能多次使用同一个元素。 -
reverse_each: 将每个元素以相反的顺序传递给给定的代码块。
转换方法¶ ↑
-
flatten: 返回一个数组,该数组是self的递归扁平化结果。 -
join: 返回一个新字符串,其中包含由字段分隔符连接的元素。 -
to_a: 返回self或包含所有元素的新数组。 -
to_ary: 返回self。 -
to_h: 返回由元素形成的新哈希。 -
transpose: 转置self,它必须是数组的数组。 -
zip: 返回一个包含self和给定数组的新数组的数组。
其他方法¶ ↑
公共类方法
来源
static VALUE
rb_ary_s_create(int argc, VALUE *argv, VALUE klass)
{
VALUE ary = ary_new(klass, argc);
if (argc > 0 && argv) {
ary_memcpy(ary, 0, argc, argv);
ARY_SET_LEN(ary, argc);
}
return ary;
}
返回一个新数组,其中填充给定的对象
Array[1, 'a', /^A/] # => [1, "a", /^A/] Array[] # => [] Array.[](1, 'a', /^A/) # => [1, "a", /^A/]
相关:请参阅 创建数组的方法。
来源
static VALUE
rb_ary_initialize(int argc, VALUE *argv, VALUE ary)
{
long len;
VALUE size, val;
rb_ary_modify(ary);
if (argc == 0) {
rb_ary_reset(ary);
RUBY_ASSERT(ARY_EMBED_P(ary));
RUBY_ASSERT(ARY_EMBED_LEN(ary) == 0);
if (rb_block_given_p()) {
rb_warning("given block not used");
}
return ary;
}
rb_scan_args(argc, argv, "02", &size, &val);
if (argc == 1 && !FIXNUM_P(size)) {
val = rb_check_array_type(size);
if (!NIL_P(val)) {
rb_ary_replace(ary, val);
return ary;
}
}
len = NUM2LONG(size);
/* NUM2LONG() may call size.to_int, ary can be frozen, modified, etc */
if (len < 0) {
rb_raise(rb_eArgError, "negative array size");
}
if (len > ARY_MAX_SIZE) {
rb_raise(rb_eArgError, "array size too big");
}
/* recheck after argument conversion */
rb_ary_modify(ary);
ary_resize_capa(ary, len);
if (rb_block_given_p()) {
long i;
if (argc == 2) {
rb_warn("block supersedes default value argument");
}
for (i=0; i<len; i++) {
rb_ary_store(ary, i, rb_yield(LONG2NUM(i)));
ARY_SET_LEN(ary, i + 1);
}
}
else {
ary_memfill(ary, 0, len, val);
ARY_SET_LEN(ary, len);
}
return ary;
}
返回一个新的数组。
如果没有给出代码块和参数,则返回一个新的空数组
Array.new # => []
如果没有给出代码块和数组参数,则返回一个包含相同元素的新数组
Array.new([:foo, 'bar', 2]) # => [:foo, "bar", 2]
如果没有给出代码块和整数参数,则返回一个新数组,其中包含给定 default_value 的多个实例
Array.new(0) # => [] Array.new(3) # => [nil, nil, nil] Array.new(2, 3) # => [3, 3]
如果给出了一个代码块,则返回给定 size 的数组;使用范围 (0...size) 中的每个 index 调用代码块;返回的数组中该 index 处的元素是代码块的返回值
Array.new(3) {|index| "Element #{index}" } # => ["Element 0", "Element 1", "Element 2"]
对于 Ruby 新手来说,一个常见的陷阱是提供一个表达式作为 default_value
array = Array.new(2, {}) array # => [{}, {}] array[0][:a] = 1 array # => [{a: 1}, {a: 1}], as array[0] and array[1] are same object
如果您希望数组的元素是不同的,则应该传递一个代码块
array = Array.new(2) { {} } array # => [{}, {}] array[0][:a] = 1 array # => [{a: 1}, {}], as array[0] and array[1] are different objects
如果第一个参数不是数组或整数可转换对象,则引发 TypeError。如果第一个参数是负整数,则引发 ArgumentError。
相关:请参阅 创建数组的方法。
来源
公共实例方法
来源
static VALUE
rb_ary_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;
}
返回一个新数组,其中包含 self 和 other_array 的 *交集*;也就是说,包含在 self 和 other_array 中找到的那些元素
[0, 1, 2, 3] & [1, 2] # => [1, 2]
省略重复项
[0, 1, 1, 0] & [0, 1] # => [0, 1]
保留 self 的顺序
[0, 1, 2] & [3, 2, 1, 0] # => [0, 1, 2]
使用方法 eql?(在 self 的每个元素中定义)标识公共元素。
相关:请参阅 合并的方法。
来源
static VALUE
rb_ary_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;
}
当给出非负整数参数 n 时,返回一个通过连接 self 的 n 个副本构建的新数组
a = ['x', 'y'] a * 3 # => ["x", "y", "x", "y", "x", "y"]
当给出字符串参数 string_separator 时,等效于 self.join(string_separator)
[0, [0, 1], {foo: 0}] * ', ' # => "0, 0, 1, {foo: 0}"
来源
VALUE
rb_ary_plus(VALUE x, VALUE y)
{
VALUE z;
long len, xlen, ylen;
y = to_ary(y);
xlen = RARRAY_LEN(x);
ylen = RARRAY_LEN(y);
len = xlen + ylen;
z = rb_ary_new2(len);
ary_memcpy(z, 0, xlen, RARRAY_CONST_PTR(x));
ary_memcpy(z, xlen, ylen, RARRAY_CONST_PTR(y));
ARY_SET_LEN(z, len);
return z;
}
返回一个新数组,其中包含 self 的所有元素,后跟 other_array 的所有元素
a = [0, 1] + [2, 3] a # => [0, 1, 2, 3]
相关:请参阅 合并的方法。
来源
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;
}
返回一个新数组,其中仅包含在 other_array 中找不到的 self 的元素;保留来自 self 的顺序
[0, 1, 1, 2, 1, 1, 3, 1, 1] - [1] # => [0, 2, 3] [0, 1, 1, 2, 1, 1, 3, 1, 1] - [3, 2, 0, :foo] # => [1, 1, 1, 1, 1, 1] [0, 1, 2] - [:foo] # => [0, 1, 2]
使用方法 eql?(在 self 的每个元素中定义)比较元素。
相关:请参阅 合并的方法。
来源
VALUE
rb_ary_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;
}
将 object 作为最后一个元素追加到 self 中;返回 self
[:foo, 'bar', 2] << :baz # => [:foo, "bar", 2, :baz]
即使 object 是另一个数组,也将其作为单个元素追加
[:foo, 'bar', 2] << [3, 4] # => [:foo, "bar", 2, [3, 4]]
相关:请参阅 赋值的方法。
来源
VALUE
rb_ary_cmp(VALUE ary1, VALUE ary2)
{
long len;
VALUE v;
ary2 = rb_check_array_type(ary2);
if (NIL_P(ary2)) return Qnil;
if (ary1 == ary2) return INT2FIX(0);
v = rb_exec_recursive_paired(recursive_cmp, ary1, ary2, ary2);
if (!UNDEF_P(v)) return v;
len = RARRAY_LEN(ary1) - RARRAY_LEN(ary2);
if (len == 0) return INT2FIX(0);
if (len > 0) return INT2FIX(1);
return INT2FIX(-1);
}
当 self 被确定为小于、等于或大于 other_array 时,返回 -1、0 或 1。
迭代 (0...self.size) 中每个索引 i
-
将
result[i]计算为self[i] <=> other_array[i]。 -
如果
result[i]为 1,则立即返回 1[0, 1, 2] <=> [0, 0, 2] # => 1
-
如果
result[i]为 -1,则立即返回 -1[0, 1, 2] <=> [0, 2, 2] # => -1
-
如果
result[i]为 0,则继续。
当每个 result 为 0 时,返回 self.size <=> other_array.size(请参阅 Integer#<=>)
[0, 1, 2] <=> [0, 1] # => 1 [0, 1, 2] <=> [0, 1, 2] # => 0 [0, 1, 2] <=> [0, 1, 2, 3] # => -1
请注意,当 other_array 大于 self 时,其尾随元素不会影响结果
[0, 1, 2] <=> [0, 1, 2, -3] # => -1 [0, 1, 2] <=> [0, 1, 2, 0] # => -1 [0, 1, 2] <=> [0, 1, 2, 3] # => -1
相关:请参阅 比较的方法。
来源
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和other_array的大小相同。 -
它们的对应元素相同;也就是说,对于
(0...self.size)中的每个索引i,self[i] == other_array[i]。
示例
[:foo, 'bar', 2] == [:foo, 'bar', 2] # => true [:foo, 'bar', 2] == [:foo, 'bar', 2.0] # => true [:foo, 'bar', 2] == [:foo, 'bar'] # => false # Different sizes. [:foo, 'bar', 2] == [:foo, 'bar', 3] # => false # Different elements.
此方法与方法 Array#eql? 不同,后者使用 Object#eql? 比较元素。
相关:请参阅 比较的方法。
来源
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 返回元素;不修改 self。
简而言之
a = [:foo, 'bar', 2] # Single argument index: returns one element. a[0] # => :foo # Zero-based index. a[-1] # => 2 # Negative index counts backwards from end. # Arguments start and length: returns an array. a[1, 2] # => ["bar", 2] a[-2, 2] # => ["bar", 2] # Negative start counts backwards from end. # Single argument range: returns an array. a[0..1] # => [:foo, "bar"] a[0..-2] # => [:foo, "bar"] # Negative range-begin counts backwards from end. a[-2..2] # => ["bar", 2] # Negative range-end counts backwards from end.
当给出单个整数参数 index 时,返回偏移量为 index 的元素
a = [:foo, 'bar', 2] a[0] # => :foo a[2] # => 2 a # => [:foo, "bar", 2]
如果 index 为负数,则从 self 的末尾向后计数
a = [:foo, 'bar', 2] a[-1] # => 2 a[-2] # => "bar"
如果 index 超出范围,则返回 nil。
当给出两个 Integer 参数 start 和 length 时,返回一个大小为 length 的新 Array,其中包含从偏移量 start 开始的连续元素
a = [:foo, 'bar', 2] a[0, 2] # => [:foo, "bar"] a[1, 2] # => ["bar", 2]
如果 start + length 大于 self.length,则返回从偏移量 start 到末尾的所有元素
a = [:foo, 'bar', 2] a[0, 4] # => [:foo, "bar", 2] a[1, 3] # => ["bar", 2] a[2, 2] # => [2]
如果 start == self.size 且 length >= 0,则返回一个新的空 Array。
如果 length 为负数,则返回 nil。
当给出单个 Range 参数 range 时,将 range.min 视为上面的 start,将 range.size 视为上面的 length
a = [:foo, 'bar', 2] a[0..1] # => [:foo, "bar"] a[1..2] # => ["bar", 2]
特殊情况:如果 range.start == a.size,则返回一个新的空 Array。
如果 range.end 为负数,则从末尾计算结束索引
a = [:foo, 'bar', 2] a[0..-1] # => [:foo, "bar", 2] a[0..-2] # => [:foo, "bar"] a[0..-3] # => [:foo]
如果 range.start 为负数,则从末尾计算开始索引
a = [:foo, 'bar', 2] a[-1..2] # => [2] a[-2..2] # => ["bar", 2] a[-3..2] # => [:foo, "bar", 2]
如果 range.start 大于数组大小,则返回 nil。
a = [:foo, 'bar', 2] a[4..1] # => nil a[4..0] # => nil a[4..-1] # => nil
当给出单个 Enumerator::ArithmeticSequence 参数 aseq 时,返回一个与序列生成的索引对应的元素的 Array。
a = ['--', 'data1', '--', 'data2', '--', 'data3'] a[(1..).step(2)] # => ["data1", "data2", "data3"]
与使用范围切片不同,如果算术序列的开始或结束大于数组大小,则抛出 RangeError。
a = ['--', 'data1', '--', 'data2', '--', 'data3'] a[(1..11).step(2)] # RangeError (((1..11).step(2)) out of range) a[(7..).step(2)] # RangeError (((7..).step(2)) out of range)
如果给出了单个参数,并且其类型不是列出的类型之一,则尝试将其转换为 Integer,如果无法转换,则引发错误
a = [:foo, 'bar', 2] # Raises TypeError (no implicit conversion of Symbol into Integer): a[:foo]
相关:请参阅 获取的方法。
来源
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]);
}
根据给定的 object 在 self 中分配元素;返回 object。
简而言之
a_orig = [:foo, 'bar', 2] # With argument index. a = a_orig.dup a[0] = 'foo' # => "foo" a # => ["foo", "bar", 2] a = a_orig.dup a[7] = 'foo' # => "foo" a # => [:foo, "bar", 2, nil, nil, nil, nil, "foo"] # With arguments start and length. a = a_orig.dup a[0, 2] = 'foo' # => "foo" a # => ["foo", 2] a = a_orig.dup a[6, 50] = 'foo' # => "foo" a # => [:foo, "bar", 2, nil, nil, nil, "foo"] # With argument range. a = a_orig.dup a[0..1] = 'foo' # => "foo" a # => ["foo", 2] a = a_orig.dup a[6..50] = 'foo' # => "foo" a # => [:foo, "bar", 2, nil, nil, nil, "foo"]
当给出 Integer 参数 index 时,将 object 分配给 self 中的一个元素。
如果 index 为非负数,则将 object 分配给偏移量为 index 的元素
a = [:foo, 'bar', 2] a[0] = 'foo' # => "foo" a # => ["foo", "bar", 2]
如果 index 大于 self.length,则扩展数组
a = [:foo, 'bar', 2] a[7] = 'foo' # => "foo" a # => [:foo, "bar", 2, nil, nil, nil, nil, "foo"]
如果 index 为负数,则从数组末尾向后计数
a = [:foo, 'bar', 2] a[-1] = 'two' # => "two" a # => [:foo, "bar", "two"]
当给出 Integer 参数 start 和 length 并且 object 不是 Array 时,删除从偏移量 start 开始的 length - 1 个元素,并在偏移量 start 处分配 object
a = [:foo, 'bar', 2] a[0, 2] = 'foo' # => "foo" a # => ["foo", 2]
如果 start 为负数,则从数组末尾向后计数
a = [:foo, 'bar', 2] a[-2, 2] = 'foo' # => "foo" a # => [:foo, "foo"]
如果 start 为非负数且在数组外部( >= self.size),则使用 nil 扩展数组,在偏移量 start 处分配 object,并忽略 length
a = [:foo, 'bar', 2] a[6, 50] = 'foo' # => "foo" a # => [:foo, "bar", 2, nil, nil, nil, "foo"]
如果 length 为零,则移动偏移量 start 和后面的元素,并在偏移量 start 处分配 object
a = [:foo, 'bar', 2] a[1, 0] = 'foo' # => "foo" a # => [:foo, "foo", "bar", 2]
如果 length 对于现有数组来说太大,则不会扩展数组
a = [:foo, 'bar', 2] a[1, 5] = 'foo' # => "foo" a # => [:foo, "foo"]
当给出 Range 参数 range 并且 object 不是 Array 时,删除从偏移量 start 开始的 length - 1 个元素,并在偏移量 start 处分配 object
a = [:foo, 'bar', 2] a[0..1] = 'foo' # => "foo" a # => ["foo", 2]
如果 range.begin 为负数,则从数组末尾向后计数
a = [:foo, 'bar', 2] a[-2..2] = 'foo' # => "foo" a # => [:foo, "foo"]
如果数组长度小于 range.begin,则使用 nil 扩展数组,在偏移量 range.begin 处分配 object,并忽略 length
a = [:foo, 'bar', 2] a[6..50] = 'foo' # => "foo" a # => [:foo, "bar", 2, nil, nil, nil, "foo"]
如果 range.end 为零,则移动偏移量 start 和后面的元素,并在偏移量 start 处分配 object
a = [:foo, 'bar', 2] a[1..0] = 'foo' # => "foo" a # => [:foo, "foo", "bar", 2]
如果 range.end 为负数,则在偏移量 start 处分配 object,保留其后的 range.end.abs -1 个元素,并删除超出范围的元素
a = [:foo, 'bar', 2] a[1..-1] = 'foo' # => "foo" a # => [:foo, "foo"] a = [:foo, 'bar', 2] a[1..-2] = 'foo' # => "foo" a # => [:foo, "foo", 2] a = [:foo, 'bar', 2] a[1..-3] = 'foo' # => "foo" a # => [:foo, "foo", "bar", 2] a = [:foo, 'bar', 2]
如果 range.end 对于现有数组来说太大,则替换数组元素,但不使用 nil 值扩展数组
a = [:foo, 'bar', 2] a[1..5] = 'foo' # => "foo" a # => [:foo, "foo"]
相关:请参阅 赋值的方法。
来源
static VALUE
rb_ary_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);
}
返回 self 和 other_array 的并集;删除重复项;保留顺序;使用 eql? 比较项。
[0, 1] | [2, 3] # => [0, 1, 2, 3] [0, 1, 1] | [2, 2, 3] # => [0, 1, 2, 3] [0, 1, 2] | [3, 2, 1, 0] # => [0, 1, 2, 3]
相关:请参阅 合并的方法。
来源
static VALUE
rb_ary_all_p(int argc, VALUE *argv, VALUE ary)
{
long i, len = RARRAY_LEN(ary);
rb_check_arity(argc, 0, 1);
if (!len) return Qtrue;
if (argc) {
if (rb_block_given_p()) {
rb_warn("given block not used");
}
for (i = 0; i < RARRAY_LEN(ary); ++i) {
if (!RTEST(rb_funcall(argv[0], idEqq, 1, RARRAY_AREF(ary, i)))) return Qfalse;
}
}
else if (!rb_block_given_p()) {
for (i = 0; i < len; ++i) {
if (!RTEST(RARRAY_AREF(ary, i))) return Qfalse;
}
}
else {
for (i = 0; i < RARRAY_LEN(ary); ++i) {
if (!RTEST(rb_yield(RARRAY_AREF(ary, i)))) return Qfalse;
}
}
return Qtrue;
}
返回 self 的每个元素是否满足给定条件。
如果没有代码块和参数,则返回 self 的每个元素是否为真值。
[[], {}, '', 0, 0.0, Object.new].all? # => true # All truthy objects.
[[], {}, '', 0, 0.0, nil].all? # => false # nil is not truthy.
[[], {}, '', 0, 0.0, false].all? # => false # false is not truthy.
如果给定参数 object,则返回对于 self 中的每个元素 ele,是否 object === ele。
[0, 0, 0].all?(0) # => true [0, 1, 2].all?(1) # => false ['food', 'fool', 'foot'].all?(/foo/) # => true ['food', 'drink'].all?(/foo/) # => false
如果给定一个代码块,则对 self 中的每个元素调用该代码块;返回该代码块是否只返回真值。
[0, 1, 2].all? { |ele| ele < 3 } # => true [0, 1, 2].all? { |ele| ele < 2 } # => false
如果同时给定代码块和参数 object,则忽略代码块,并使用上面的 object。
特殊情况:如果 self 为空,则返回 true (无论给定任何参数或代码块)。
相关:请参阅 查询方法。
来源
static VALUE
rb_ary_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 的任何元素是否满足给定条件。
如果没有代码块和参数,则返回 self 的任何元素是否为真值。
[nil, false, []].any? # => true # Array object is truthy. [nil, false, {}].any? # => true # Hash object is truthy. [nil, false, ''].any? # => true # String object is truthy. [nil, false].any? # => false # Nil and false are not truthy.
如果给定参数 object,则返回对于 self 中的任何元素 ele,是否 object === ele。
[nil, false, 0].any?(0) # => true [nil, false, 1].any?(0) # => false [nil, false, 'food'].any?(/foo/) # => true [nil, false, 'food'].any?(/bar/) # => false
如果给定一个代码块,则对 self 中的每个元素调用该代码块;返回该代码块是否返回任何真值。
[0, 1, 2].any? {|ele| ele < 1 } # => true [0, 1, 2].any? {|ele| ele < 0 } # => false
如果同时给定代码块和参数 object,则忽略代码块,并使用上面的 object。
特殊情况:如果 self 为空,则返回 false (无论给定任何参数或代码块)。
相关:请参阅 查询方法。
将 objects 中的每个参数追加到 self;返回 self。
a = [:foo, 'bar', 2] # => [:foo, "bar", 2] a.push(:baz, :bat) # => [:foo, "bar", 2, :baz, :bat]
将每个参数作为单个元素追加,即使它是另一个数组。
a = [:foo, 'bar', 2] # => [:foo, "bar", 2] a.push([:baz, :bat], [:bam, :bad]) # => [:foo, "bar", 2, [:baz, :bat], [:bam, :bad]]
相关:请参阅 赋值的方法。
来源
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;
}
返回 self 中第一个元素 ele,使得 ele 是一个数组并且 ele[0] == object。
a = [{foo: 0}, [2, 4], [4, 5, 6], [4, 5]] a.assoc(4) # => [4, 5, 6]
如果未找到此类元素,则返回 nil。
相关:Array#rassoc;另请参阅 获取方法。
来源
VALUE
rb_ary_at(VALUE ary, VALUE pos)
{
return rb_ary_entry(ary, NUM2LONG(pos));
}
返回 self 中由给定 index 指定的元素,如果不存在此类元素,则返回 nil;index 必须是 可转换为整数的对象。
对于非负 index,返回 self 中偏移量为 index 的元素。
a = [:foo, 'bar', 2] a.at(0) # => :foo a.at(2) # => 2 a.at(2.0) # => 2
对于负 index,从 self 的末尾向后计数。
a.at(-2) # => "bar"
来源
来源
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 中找到的元素的整数索引,如果搜索未找到合适的元素,则返回 nil。
请参阅 二分搜索。
相关:请参阅 获取的方法。
来源
VALUE
rb_ary_clear(VALUE ary)
{
rb_ary_modify_check(ary);
if (ARY_SHARED_P(ary)) {
rb_ary_unshare(ary);
FL_SET_EMBED(ary);
ARY_SET_EMBED_LEN(ary, 0);
}
else {
ARY_SET_LEN(ary, 0);
if (ARY_DEFAULT_SIZE * 2 < ARY_CAPA(ary)) {
ary_resize_capa(ary, ARY_DEFAULT_SIZE * 2);
}
}
ary_verify(ary);
return ary;
}
从 self 中删除所有元素;返回 self。
a = [:foo, 'bar', 2] a.clear # => []
相关:请参阅 删除方法。
来源
static VALUE
rb_ary_collect(VALUE ary)
{
long i;
VALUE collect;
RETURN_SIZED_ENUMERATOR(ary, 0, 0, ary_enum_length);
collect = rb_ary_new2(RARRAY_LEN(ary));
for (i = 0; i < RARRAY_LEN(ary); i++) {
rb_ary_push(collect, rb_yield(RARRAY_AREF(ary, i)));
}
return collect;
}
如果给定代码块,则对 self 的每个元素调用该代码块;返回一个新数组,其元素是该代码块的返回值。
a = [:foo, 'bar', 2] a1 = a.map {|element| element.class } a1 # => [Symbol, String, Integer]
如果没有给定代码块,则返回一个新的 Enumerator。
来源
static VALUE
rb_ary_collect_bang(VALUE ary)
{
long i;
RETURN_SIZED_ENUMERATOR(ary, 0, 0, ary_enum_length);
rb_ary_modify(ary);
for (i = 0; i < RARRAY_LEN(ary); i++) {
rb_ary_store(ary, i, rb_yield(RARRAY_AREF(ary, i)));
}
return ary;
}
如果给定代码块,则对 self 的每个元素调用该代码块,并用该代码块的返回值替换该元素;返回 self。
a = [:foo, 'bar', 2] a.map! { |element| element.class } # => [Symbol, String, Integer]
如果没有给定代码块,则返回一个新的 Enumerator。
来源
static VALUE
rb_ary_combination(VALUE ary, VALUE num)
{
long i, n, len;
n = NUM2LONG(num);
RETURN_SIZED_ENUMERATOR(ary, 1, &num, rb_ary_combination_size);
len = RARRAY_LEN(ary);
if (n < 0 || len < n) {
/* yield nothing */
}
else if (n == 0) {
rb_yield(rb_ary_new2(0));
}
else if (n == 1) {
for (i = 0; i < RARRAY_LEN(ary); i++) {
rb_yield(rb_ary_new3(1, RARRAY_AREF(ary, i)));
}
}
else {
VALUE ary0 = ary_make_shared_copy(ary); /* private defensive copy of ary */
volatile VALUE t0;
long *stack = ALLOCV_N(long, t0, n+1);
RBASIC_CLEAR_CLASS(ary0);
combinate0(len, n, stack, ary0);
ALLOCV_END(t0);
RBASIC_SET_CLASS_RAW(ary0, rb_cArray);
}
return ary;
}
当给定一个代码块和一个正的 可转换为整数的对象 参数 count (0 < count <= self.size) 时,对 self 的大小为 count 的每个组合调用该代码块;返回 self。
a = %w[a b c] # => ["a", "b", "c"] a.combination(2) {|combination| p combination } # => ["a", "b", "c"]
输出
["a", "b"] ["a", "c"] ["b", "c"]
不能保证生成的组合的顺序。
当 count 为零时,使用一个新的空数组调用该代码块一次。
a.combination(0) {|combination| p combination } [].combination(0) {|combination| p combination }
输出
[] []
当 count 为负数或大于 self.size 且 self 为非空时,不调用该代码块。
a.combination(-1) {|combination| fail 'Cannot happen' } # => ["a", "b", "c"] a.combination(4) {|combination| fail 'Cannot happen' } # => ["a", "b", "c"]
如果没有给定代码块,则返回一个新的 Enumerator。
相关:Array#permutation;另请参阅 迭代方法。
来源
static VALUE
rb_ary_compact(VALUE ary)
{
ary = rb_ary_dup(ary);
rb_ary_compact_bang(ary);
return ary;
}
返回一个新数组,其中仅包含 self 中非 nil 的元素;保留元素顺序。
a = [nil, 0, nil, false, nil, '', nil, [], nil, {}] a.compact # => [0, false, "", [], {}]
相关:Array#compact!;另请参阅 删除方法。
来源
static VALUE
rb_ary_compact_bang(VALUE ary)
{
VALUE *p, *t, *end;
long n;
rb_ary_modify(ary);
p = t = (VALUE *)RARRAY_CONST_PTR(ary); /* WB: no new reference */
end = p + RARRAY_LEN(ary);
while (t < end) {
if (NIL_P(*t)) t++;
else *p++ = *t++;
}
n = p - RARRAY_CONST_PTR(ary);
if (RARRAY_LEN(ary) == n) {
return Qnil;
}
ary_resize_smaller(ary, n);
return ary;
}
从 self 中删除所有 nil 元素;如果删除了任何元素,则返回 self,否则返回 nil。
a = [nil, 0, nil, false, nil, '', nil, [], nil, {}] a.compact! # => [0, false, "", [], {}] a # => [0, false, "", [], {}] a.compact! # => nil
相关:Array#compact;另请参阅 删除方法。
来源
static VALUE
rb_ary_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;
}
将 other_arrays 中每个数组的所有元素添加到 self;返回 self。
a = [0, 1] a.concat(['two', 'three'], [:four, :five], a) # => [0, 1, "two", "three", :four, :five, 0, 1]
相关:请参阅 赋值的方法。
来源
static VALUE
rb_ary_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);
}
返回指定元素的计数。
如果没有参数和代码块,则返回所有元素的计数。
[0, :one, 'two', 3, 3.0].count # => 5
如果给定参数 object,则返回 == object 的元素的计数。
[0, :one, 'two', 3, 3.0].count(3) # => 2
如果没有参数且给定代码块,则对每个元素调用该代码块;返回代码块返回真值的元素的计数。
[0, 1, 2, 3].count {|element| element > 1 } # => 2
如果给定参数 object 和代码块,则发出警告,忽略该代码块,并返回 == object 的元素的计数。
相关:请参阅 查询方法。
来源
static VALUE
rb_ary_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;
}
如果给定一个代码块,则可能调用该代码块,具体取决于参数 count 的值;count 必须是 可转换为整数的对象 或 nil。
当 count 为正数时,对每个元素调用该代码块,然后重复执行此操作,直到执行了 count 次;返回 nil。
output = [] [0, 1].cycle(2) {|element| output.push(element) } # => nil output # => [0, 1, 0, 1]
当 count 为零或负数时,不调用该代码块。
[0, 1].cycle(0) {|element| fail 'Cannot happen' } # => nil [0, 1].cycle(-1) {|element| fail 'Cannot happen' } # => nil
当 count 为 nil 时,将永远循环。
# Prints 0 and 1 forever. [0, 1].cycle {|element| puts element } [0, 1].cycle(nil) {|element| puts element }
如果没有给定代码块,则返回一个新的 Enumerator。
相关:请参阅 迭代方法。
来源
VALUE
rb_ary_delete(VALUE ary, VALUE item)
{
VALUE v = item;
long i1, i2;
for (i1 = i2 = 0; i1 < RARRAY_LEN(ary); i1++) {
VALUE e = RARRAY_AREF(ary, i1);
if (rb_equal(e, item)) {
v = e;
continue;
}
if (i1 != i2) {
rb_ary_store(ary, i2, e);
}
i2++;
}
if (RARRAY_LEN(ary) == i2) {
if (rb_block_given_p()) {
return rb_yield(item);
}
return Qnil;
}
ary_resize_smaller(ary, i2);
ary_verify(ary);
return v;
}
从 self 中删除零个或多个元素。
如果没有给定代码块,则从 self 中删除每个元素 ele,使得 ele == object;返回最后删除的元素。
a = [0, 1, 2, 2.0] a.delete(2) # => 2.0 a # => [0, 1]
如果没有删除任何元素,则返回 nil。
a.delete(2) # => nil
如果给定代码块,则从 self 中删除每个元素 ele,使得 ele == object。
如果找到任何此类元素,则忽略代码块并返回最后删除的元素。
a = [0, 1, 2, 2.0] a.delete(2) {|element| fail 'Cannot happen' } # => 2.0 a # => [0, 1]
如果未找到此类元素,则返回代码块的返回值。
a.delete(2) {|element| "Element #{element} not found." } # => "Element 2 not found."
相关:请参阅 删除方法。
来源
static VALUE
rb_ary_delete_at_m(VALUE ary, VALUE pos)
{
return rb_ary_delete_at(ary, NUM2LONG(pos));
}
删除 self 中给定 index 的元素,index 必须是 可转换为整数的对象。
当 index 为非负数时,删除偏移量为 index 的元素。
a = [:foo, 'bar', 2] a.delete_at(1) # => "bar" a # => [:foo, 2]
当 index 为负数时,从数组末尾向后计数。
a = [:foo, 'bar', 2] a.delete_at(-2) # => "bar" a # => [:foo, 2]
当 index 超出范围时,返回 nil。
a = [:foo, 'bar', 2] a.delete_at(3) # => nil a.delete_at(-4) # => nil
相关:请参阅 删除方法。
来源
static VALUE
rb_ary_delete_if(VALUE ary)
{
ary_verify(ary);
RETURN_SIZED_ENUMERATOR(ary, 0, 0, ary_enum_length);
ary_reject_bang(ary);
return ary;
}
如果给定代码块,则对 self 的每个元素调用该代码块;如果该代码块返回真值,则删除该元素;返回 self。
a = [:foo, 'bar', 2, 'bat'] a.delete_if {|element| element.to_s.start_with?('b') } # => [:foo, 2]
如果没有给定代码块,则返回一个新的 Enumerator。
相关:请参阅 删除方法。
来源
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;
}
返回一个新数组,其中仅包含 self 中未在任何给定的 other_arrays 中找到的元素;使用 eql? 比较项;保留来自 self 的顺序。
[0, 1, 1, 2, 1, 1, 3, 1, 1].difference([1]) # => [0, 2, 3] [0, 1, 2, 3].difference([3, 0], [1, 3]) # => [2] [0, 1, 2].difference([4]) # => [0, 1, 2] [0, 1, 2].difference # => [0, 1, 2]
如果没有给出任何参数,则返回 self 的副本。
来源
static VALUE
rb_ary_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);
}
查找并返回由 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_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 的所有元素,但前 count 个元素除外,其中 count 是一个非负整数;不修改 self。
示例
a = [0, 1, 2, 3, 4, 5] a.drop(0) # => [0, 1, 2, 3, 4, 5] a.drop(1) # => [1, 2, 3, 4, 5] a.drop(2) # => [2, 3, 4, 5] a.drop(9) # => []
相关:请参阅 获取的方法。
来源
static VALUE
rb_ary_drop_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 的每个连续元素调用该代码块;如果该代码块返回 false 或 nil,则停止;返回一个新数组,省略 该代码块返回真值的元素;不修改 self。
a = [0, 1, 2, 3, 4, 5] a.drop_while {|element| element < 3 } # => [3, 4, 5]
如果没有给定代码块,则返回一个新的 Enumerator。
相关:请参阅 获取的方法。
来源
VALUE
rb_ary_each(VALUE ary)
{
long i;
ary_verify(ary);
RETURN_SIZED_ENUMERATOR(ary, 0, 0, ary_enum_length);
for (i=0; i<RARRAY_LEN(ary); i++) {
rb_yield(RARRAY_AREF(ary, i));
}
return ary;
}
如果给定一个代码块,则遍历 self 的元素,将每个元素传递给该代码块;返回 self。
a = [:foo, 'bar', 2] a.each {|element| puts "#{element.class} #{element}" }
输出
Symbol foo String bar Integer 2
允许在迭代期间修改数组。
a = [:foo, 'bar', 2] a.each {|element| puts element; a.clear if element.to_s.start_with?('b') }
输出
foo bar
如果没有给定代码块,则返回一个新的 Enumerator。
相关:请参阅 迭代方法。
来源
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 的元素,将每个数组索引传递给该代码块;返回 self。
a = [:foo, 'bar', 2] a.each_index {|index| puts "#{index} #{a[index]}" }
输出
0 foo 1 bar 2 2
允许在迭代期间修改数组。
a = [:foo, 'bar', 2] a.each_index {|index| puts index; a.clear if index > 0 } a # => []
输出
0 1
如果没有给定代码块,则返回一个新的 Enumerator。
相关:请参阅 迭代方法。
来源
static VALUE
rb_ary_empty_p(VALUE ary)
{
return RBOOL(RARRAY_LEN(ary) == 0);
}
如果 self 中的元素计数为零,则返回 true,否则返回 false。
相关:请参阅 查询方法。
来源
static VALUE
rb_ary_eql(VALUE ary1, VALUE ary2)
{
if (ary1 == ary2) return Qtrue;
if (!RB_TYPE_P(ary2, T_ARRAY)) return Qfalse;
if (RARRAY_LEN(ary1) != RARRAY_LEN(ary2)) return Qfalse;
if (RARRAY_CONST_PTR(ary1) == RARRAY_CONST_PTR(ary2)) return Qtrue;
return rb_exec_recursive_paired(recursive_eql, ary1, ary2, ary2);
}
如果 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_fetch(int argc, VALUE *argv, VALUE ary)
{
VALUE pos, ifnone;
long block_given;
long idx;
rb_scan_args(argc, argv, "11", &pos, &ifnone);
block_given = rb_block_given_p();
if (block_given && argc == 2) {
rb_warn("block supersedes default value argument");
}
idx = NUM2LONG(pos);
if (idx < 0) {
idx += RARRAY_LEN(ary);
}
if (idx < 0 || RARRAY_LEN(ary) <= idx) {
if (block_given) return rb_yield(pos);
if (argc == 1) {
rb_raise(rb_eIndexError, "index %ld outside of array bounds: %ld...%ld",
idx - (idx < 0 ? RARRAY_LEN(ary) : 0), -RARRAY_LEN(ary), RARRAY_LEN(ary));
}
return ifnone;
}
return RARRAY_AREF(ary, idx);
}
如果 index 在范围内,则返回 self 中偏移量为 index 的元素;index 必须是 可转换为整数的对象。
如果只有一个参数 index 且没有代码块,则返回偏移量为 index 的元素。
a = [:foo, 'bar', 2] a.fetch(1) # => "bar" a.fetch(1.1) # => "bar"
如果 index 为负数,则从数组末尾开始计数。
a = [:foo, 'bar', 2] a.fetch(-1) # => 2 a.fetch(-2) # => "bar"
如果具有参数 index 和 default_value (可以是任何对象) 且没有代码块,则如果 index 超出范围,则返回 default_value。
a = [:foo, 'bar', 2] a.fetch(1, nil) # => "bar" a.fetch(3, :foo) # => :foo
如果具有参数 index 和代码块,则如果 index 在范围内,则返回偏移量为 index 的元素(并且不调用该代码块);否则,使用 index 调用该代码块并返回其返回值。
a = [:foo, 'bar', 2] a.fetch(1) {|index| raise 'Cannot happen' } # => "bar" a.fetch(50) {|index| "Value for #{index}" } # => "Value for 50"
相关:请参阅 获取的方法。
来源
# File array.rb, line 210 def fetch_values(*indexes, &block) indexes.map! { |i| fetch(i, &block) } indexes end
如果没有给定代码块,则返回一个新数组,其中包含 self 中由 indexes 指定的偏移量处的元素。每个 indexes 必须是 可转换为整数的对象。
a = [:foo, :bar, :baz] a.fetch_values(2, 0) # => [:baz, :foo] a.fetch_values(2.1, 0) # => [:baz, :foo] a.fetch_values # => []
对于负索引,从数组末尾向后计数。
a.fetch_values(-2, -1) # [:bar, :baz]
如果没有给定代码块,则如果任何索引超出范围,则引发异常。
如果给定一个代码块,则对于每个索引
-
如果索引在范围内,则使用
self的一个元素(如上所述)。 -
否则,使用该索引调用该代码块并使用该代码块的返回值。
示例
a = [:foo, :bar, :baz] a.fetch_values(1, 0, 42, 777) { |index| index.to_s } # => [:bar, :foo, "42", "777"]
相关:请参阅 获取的方法。
来源
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 添加元素;始终返回 self(绝不会返回新数组)。
简而言之
# Non-negative start. ['a', 'b', 'c', 'd'].fill('-', 1, 2) # => ["a", "-", "-", "d"] ['a', 'b', 'c', 'd'].fill(1, 2) {|e| e.to_s } # => ["a", "1", "2", "d"] # Extends with specified values if necessary. ['a', 'b', 'c', 'd'].fill('-', 3, 2) # => ["a", "b", "c", "-", "-"] ['a', 'b', 'c', 'd'].fill(3, 2) {|e| e.to_s } # => ["a", "b", "c", "3", "4"] # Fills with nils if necessary. ['a', 'b', 'c', 'd'].fill('-', 6, 2) # => ["a", "b", "c", "d", nil, nil, "-", "-"] ['a', 'b', 'c', 'd'].fill(6, 2) {|e| e.to_s } # => ["a", "b", "c", "d", nil, nil, "6", "7"] # For negative start, counts backwards from the end. ['a', 'b', 'c', 'd'].fill('-', -3, 3) # => ["a", "-", "-", "-"] ['a', 'b', 'c', 'd'].fill(-3, 3) {|e| e.to_s } # => ["a", "1", "2", "3"] # Range. ['a', 'b', 'c', 'd'].fill('-', 1..2) # => ["a", "-", "-", "d"] ['a', 'b', 'c', 'd'].fill(1..2) {|e| e.to_s } # => ["a", "1", "2", "d"]
当给定参数 start 和 count 时,它们选择要替换的 self 的元素;每个参数都必须是可转换为整数的对象(或 nil)。
-
start指定要替换的第一个元素的从零开始的偏移量;nil表示零。 -
count是要替换的连续元素的数量;nil表示“所有其余元素”。
如果给定参数 object,则该对象用于所有替换。
o = Object.new # => #<Object:0x0000014e7bff7600> a = ['a', 'b', 'c', 'd'] # => ["a", "b", "c", "d"] a.fill(o, 1, 2) # => ["a", #<Object:0x0000014e7bff7600>, #<Object:0x0000014e7bff7600>, "d"]
如果给定了代码块,则为每个要替换的元素调用一次该代码块;传递给代码块的值是要替换元素的索引(而不是元素本身);代码块的返回值将替换该元素。
a = ['a', 'b', 'c', 'd'] # => ["a", "b", "c", "d"] a.fill(1, 2) {|element| element.to_s } # => ["a", "1", "2", "d"]
对于参数 start 和 count:
-
如果
start为非负数,则替换从偏移量start开始的count个元素。['a', 'b', 'c', 'd'].fill('-', 0, 2) # => ["-", "-", "c", "d"] ['a', 'b', 'c', 'd'].fill('-', 1, 2) # => ["a", "-", "-", "d"] ['a', 'b', 'c', 'd'].fill('-', 2, 2) # => ["a", "b", "-", "-"] ['a', 'b', 'c', 'd'].fill(0, 2) {|e| e.to_s } # => ["0", "1", "c", "d"] ['a', 'b', 'c', 'd'].fill(1, 2) {|e| e.to_s } # => ["a", "1", "2", "d"] ['a', 'b', 'c', 'd'].fill(2, 2) {|e| e.to_s } # => ["a", "b", "2", "3"]
如果需要,扩展
self。['a', 'b', 'c', 'd'].fill('-', 3, 2) # => ["a", "b", "c", "-", "-"] ['a', 'b', 'c', 'd'].fill('-', 4, 2) # => ["a", "b", "c", "d", "-", "-"] ['a', 'b', 'c', 'd'].fill(3, 2) {|e| e.to_s } # => ["a", "b", "c", "3", "4"] ['a', 'b', 'c', 'd'].fill(4, 2) {|e| e.to_s } # => ["a", "b", "c", "d", "4", "5"]
如果需要,用
nil填充。['a', 'b', 'c', 'd'].fill('-', 5, 2) # => ["a", "b", "c", "d", nil, "-", "-"] ['a', 'b', 'c', 'd'].fill('-', 6, 2) # => ["a", "b", "c", "d", nil, nil, "-", "-"] ['a', 'b', 'c', 'd'].fill(5, 2) {|e| e.to_s } # => ["a", "b", "c", "d", nil, "5", "6"] ['a', 'b', 'c', 'd'].fill(6, 2) {|e| e.to_s } # => ["a", "b", "c", "d", nil, nil, "6", "7"]
如果
count为非正数,则不执行任何操作。['a', 'b', 'c', 'd'].fill('-', 2, 0) # => ["a", "b", "c", "d"] ['a', 'b', 'c', 'd'].fill('-', 2, -100) # => ["a", "b", "c", "d"] ['a', 'b', 'c', 'd'].fill('-', 6, -100) # => ["a", "b", "c", "d"] ['a', 'b', 'c', 'd'].fill(2, 0) {|e| fail 'Cannot happen' } # => ["a", "b", "c", "d"] ['a', 'b', 'c', 'd'].fill(2, -100) {|e| fail 'Cannot happen' } # => ["a", "b", "c", "d"] ['a', 'b', 'c', 'd'].fill(6, -100) {|e| fail 'Cannot happen' } # => ["a", "b", "c", "d"]
-
如果
start为负数,则从self的末尾向后计数。['a', 'b', 'c', 'd'].fill('-', -4, 3) # => ["-", "-", "-", "d"] ['a', 'b', 'c', 'd'].fill('-', -3, 3) # => ["a", "-", "-", "-"] ['a', 'b', 'c', 'd'].fill(-4, 3) {|e| e.to_s } # => ["0", "1", "2", "d"] ['a', 'b', 'c', 'd'].fill(-3, 3) {|e| e.to_s } # => ["a", "1", "2", "3"]
如果需要,扩展
self。['a', 'b', 'c', 'd'].fill('-', -2, 3) # => ["a", "b", "-", "-", "-"] ['a', 'b', 'c', 'd'].fill('-', -1, 3) # => ["a", "b", "c", "-", "-", "-"] ['a', 'b', 'c', 'd'].fill(-2, 3) {|e| e.to_s } # => ["a", "b", "2", "3", "4"] ['a', 'b', 'c', 'd'].fill(-1, 3) {|e| e.to_s } # => ["a", "b", "c", "3", "4", "5"]
如果
start为负数且超出范围,则从self的开头开始。['a', 'b', 'c', 'd'].fill('-', -5, 2) # => ["-", "-", "c", "d"] ['a', 'b', 'c', 'd'].fill('-', -6, 2) # => ["-", "-", "c", "d"] ['a', 'b', 'c', 'd'].fill(-5, 2) {|e| e.to_s } # => ["0", "1", "c", "d"] ['a', 'b', 'c', 'd'].fill(-6, 2) {|e| e.to_s } # => ["0", "1", "c", "d"]
如果
count为非正数,则不执行任何操作。['a', 'b', 'c', 'd'].fill('-', -2, 0) # => ["a", "b", "c", "d"] ['a', 'b', 'c', 'd'].fill('-', -2, -1) # => ["a", "b", "c", "d"] ['a', 'b', 'c', 'd'].fill(-2, 0) {|e| fail 'Cannot happen' } # => ["a", "b", "c", "d"] ['a', 'b', 'c', 'd'].fill(-2, -1) {|e| fail 'Cannot happen' } # => ["a", "b", "c", "d"]
当给定参数 range 时,它必须是 Range 对象,其成员是数值;其 begin 和 end 值确定要替换的 self 的元素。
-
如果
begin和end都是正数,则它们指定要替换的第一个和最后一个元素。['a', 'b', 'c', 'd'].fill('-', 1..2) # => ["a", "-", "-", "d"] ['a', 'b', 'c', 'd'].fill(1..2) {|e| e.to_s } # => ["a", "1", "2", "d"]
如果
end小于begin,则不替换任何元素。['a', 'b', 'c', 'd'].fill('-', 2..1) # => ["a", "b", "c", "d"] ['a', 'b', 'c', 'd'].fill(2..1) {|e| e.to_s } # => ["a", "b", "c", "d"]
-
如果任一为负数(或两者都为负数),则从
self的末尾向后计数。['a', 'b', 'c', 'd'].fill('-', -3..2) # => ["a", "-", "-", "d"] ['a', 'b', 'c', 'd'].fill('-', 1..-2) # => ["a", "-", "-", "d"] ['a', 'b', 'c', 'd'].fill('-', -3..-2) # => ["a", "-", "-", "d"] ['a', 'b', 'c', 'd'].fill(-3..2) {|e| e.to_s } # => ["a", "1", "2", "d"] ['a', 'b', 'c', 'd'].fill(1..-2) {|e| e.to_s } # => ["a", "1", "2", "d"] ['a', 'b', 'c', 'd'].fill(-3..-2) {|e| e.to_s } # => ["a", "1", "2", "d"]
-
如果
end值被排除(请参阅Range#exclude_end?),则省略最后一个替换。['a', 'b', 'c', 'd'].fill('-', 1...2) # => ["a", "-", "c", "d"] ['a', 'b', 'c', 'd'].fill('-', 1...-2) # => ["a", "-", "c", "d"] ['a', 'b', 'c', 'd'].fill(1...2) {|e| e.to_s } # => ["a", "1", "c", "d"] ['a', 'b', 'c', 'd'].fill(1...-2) {|e| e.to_s } # => ["a", "1", "c", "d"]
-
如果范围是无限的(请参阅 无限范围),则替换到
self末尾的元素。['a', 'b', 'c', 'd'].fill('-', 1..) # => ["a", "-", "-", "-"] ['a', 'b', 'c', 'd'].fill(1..) {|e| e.to_s } # => ["a", "1", "2", "3"]
-
如果范围是无始的(请参阅 无始范围),则替换从
self开头的元素。['a', 'b', 'c', 'd'].fill('-', ..2) # => ["-", "-", "-", "d"] ['a', 'b', 'c', 'd'].fill(..2) {|e| e.to_s } # => ["0", "1", "2", "d"]
相关:请参阅 赋值的方法。
如果给定了代码块,则使用 self 的每个元素调用该代码块;返回一个新的数组,其中包含 self 中代码块返回真值的那些元素。
a = [:foo, 'bar', 2, :bam] a.select {|element| element.to_s.start_with?('b') } # => ["bar", :bam]
如果没有给定代码块,则返回一个新的 Enumerator。
相关:请参阅 获取的方法。
如果给定了代码块,则使用 self 的每个元素调用该代码块;从 self 中删除代码块返回 false 或 nil 的那些元素。
如果删除了任何元素,则返回 self。
a = [:foo, 'bar', 2, :bam] a.select! {|element| element.to_s.start_with?('b') } # => ["bar", :bam]
如果没有删除任何元素,则返回 nil。
如果没有给定代码块,则返回一个新的 Enumerator。
相关:请参阅 删除方法。
来源
# File array.rb, line 129 def first n = unspecified = true if Primitive.mandatory_only? Primitive.attr! :leaf Primitive.cexpr! %q{ ary_first(self) } else if unspecified Primitive.cexpr! %q{ ary_first(self) } else Primitive.cexpr! %q{ ary_take_first_or_last_n(self, NUM2LONG(n), ARY_TAKE_FIRST) } end end end
从 self 返回元素,或者返回 nil;不修改 self。
如果未给出任何参数,则返回第一个元素(如果可用)。
a = [:foo, 'bar', 2] a.first # => :foo a # => [:foo, "bar", 2]
如果 self 为空,则返回 nil。
[].first # => nil
如果给定了非负整数参数 count,则返回一个新数组,其中包含前 count 个元素(如果可用)。
a.first(0) # => [] a.first(2) # => [:foo, "bar"] a.first(50) # => [:foo, "bar", 2]
相关:请参阅 查询方法。
来源
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 的递归扁平化,递归到 depth 层;depth 必须是可转换为整数的对象或 nil。在每一层递归中:
-
每个作为数组的元素都将被“扁平化”(即,替换为其单独的数组元素)。
-
每个不是数组的元素都保持不变(即使该元素是一个具有实例方法
flatten的对象)。
如果使用非负整数参数 depth,则递归地通过 depth 层进行扁平化。
a = [ 0, [ 1, [2, 3], 4 ], 5, {foo: 0}, Set.new([6, 7]) ] a # => [0, [1, [2, 3], 4], 5, {:foo=>0}, #<Set: {6, 7}>] a.flatten(0) # => [0, [1, [2, 3], 4], 5, {:foo=>0}, #<Set: {6, 7}>] a.flatten(1 ) # => [0, 1, [2, 3], 4, 5, {:foo=>0}, #<Set: {6, 7}>] a.flatten(1.1) # => [0, 1, [2, 3], 4, 5, {:foo=>0}, #<Set: {6, 7}>] a.flatten(2) # => [0, 1, 2, 3, 4, 5, {:foo=>0}, #<Set: {6, 7}>] a.flatten(3) # => [0, 1, 2, 3, 4, 5, {:foo=>0}, #<Set: {6, 7}>]
如果使用 nil 或负数 depth,则扁平化所有层。
a.flatten # => [0, 1, 2, 3, 4, 5, {:foo=>0}, #<Set: {6, 7}>] a.flatten(-1) # => [0, 1, 2, 3, 4, 5, {:foo=>0}, #<Set: {6, 7}>]
相关:Array#flatten!;另请参阅 用于转换的方法。
来源
static VALUE
rb_ary_flatten_bang(int argc, VALUE *argv, VALUE ary)
{
int mod = 0, level = -1;
VALUE result, lv;
lv = (rb_check_arity(argc, 0, 1) ? argv[0] : Qnil);
rb_ary_modify_check(ary);
if (!NIL_P(lv)) level = NUM2INT(lv);
if (level == 0) return Qnil;
result = flatten(ary, level);
if (result == ary) {
return Qnil;
}
if (!(mod = ARY_EMBED_P(result))) rb_ary_freeze(result);
rb_ary_replace(ary, result);
if (mod) ARY_SET_EMBED_LEN(result, 0);
return ary;
}
将 self 作为 self 的递归扁平化返回,递归到 depth 层;depth 必须是可转换为整数的对象或 nil。在每一层递归中:
-
每个作为数组的元素都将被“扁平化”(即,替换为其单独的数组元素)。
-
每个不是数组的元素都保持不变(即使该元素是一个具有实例方法
flatten的对象)。
如果没有扁平化任何元素,则返回 nil。
如果使用非负整数参数 depth,则递归地通过 depth 层进行扁平化。
a = [ 0, [ 1, [2, 3], 4 ], 5, {foo: 0}, Set.new([6, 7]) ] a # => [0, [1, [2, 3], 4], 5, {:foo=>0}, #<Set: {6, 7}>] a.dup.flatten!(1) # => [0, 1, [2, 3], 4, 5, {:foo=>0}, #<Set: {6, 7}>] a.dup.flatten!(1.1) # => [0, 1, [2, 3], 4, 5, {:foo=>0}, #<Set: {6, 7}>] a.dup.flatten!(2) # => [0, 1, 2, 3, 4, 5, {:foo=>0}, #<Set: {6, 7}>] a.dup.flatten!(3) # => [0, 1, 2, 3, 4, 5, {:foo=>0}, #<Set: {6, 7}>]
如果使用 nil 或负数参数 depth,则扁平化所有层。
a.dup.flatten! # => [0, 1, 2, 3, 4, 5, {:foo=>0}, #<Set: {6, 7}>] a.dup.flatten!(-1) # => [0, 1, 2, 3, 4, 5, {:foo=>0}, #<Set: {6, 7}>]
相关:Array#flatten;另请参阅 用于赋值的方法。
来源
VALUE
rb_ary_freeze(VALUE ary)
{
RUBY_ASSERT(RB_TYPE_P(ary, T_ARRAY));
if (OBJ_FROZEN(ary)) return ary;
if (!ARY_EMBED_P(ary) && !ARY_SHARED_P(ary) && !ARY_SHARED_ROOT_P(ary)) {
ary_shrink_capa(ary);
}
return rb_obj_freeze(ary);
}
冻结 self(如果尚未冻结);返回 self。
a = [] a.frozen? # => false a.freeze a.frozen? # => true
不能再对 self 进行任何更改;如果尝试更改,则会引发 FrozenError。
相关:Kernel#frozen?。
来源
static VALUE
rb_ary_hash(VALUE ary)
{
return rb_ary_hash_values(RARRAY_LEN(ary), RARRAY_CONST_PTR(ary));
}
返回 self 的整数哈希值。
具有相同内容的两个数组将具有相同的哈希值(并且将使用 eql? 进行比较)。
['a', 'b'].hash == ['a', 'b'].hash # => true ['a', 'b'].hash == ['a', 'c'].hash # => false ['a', 'b'].hash == ['a'].hash # => 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;
}
返回对于 self 中的某些元素 element,是否 object == element。
[0, 1, 2].include?(2) # => true [0, 1, 2].include?(2.0) # => true [0, 1, 2].include?(2.1) # => false
相关:请参阅 查询方法。
返回指定元素的从零开始的整数索引,如果未找到,则返回 nil。
如果仅给定了参数 object,则返回第一个元素 element 的索引,其中 object == element。
a = [:foo, 'bar', 2, 'bar'] a.index('bar') # => 1
如果未找到此类元素,则返回 nil。
如果仅给定了代码块,则使用每个连续的元素调用该代码块;返回第一个代码块返回真值的元素的索引。
a = [:foo, 'bar', 2, 'bar'] a.index {|element| element == 'bar' } # => 1
如果代码块从未返回真值,则返回 nil。
如果既未给出参数,也未给出代码块,则返回一个新的 Enumerator。
相关:请参阅 查询方法。
来源
VALUE
rb_ary_replace(VALUE copy, VALUE orig)
{
rb_ary_modify_check(copy);
orig = to_ary(orig);
if (copy == orig) return copy;
rb_ary_reset(copy);
/* orig has enough space to embed the contents of orig. */
if (RARRAY_LEN(orig) <= ary_embed_capa(copy)) {
RUBY_ASSERT(ARY_EMBED_P(copy));
ary_memcpy(copy, 0, RARRAY_LEN(orig), RARRAY_CONST_PTR(orig));
ARY_SET_EMBED_LEN(copy, RARRAY_LEN(orig));
}
/* orig is embedded but copy does not have enough space to embed the
* contents of orig. */
else if (ARY_EMBED_P(orig)) {
long len = ARY_EMBED_LEN(orig);
VALUE *ptr = ary_heap_alloc_buffer(len);
FL_UNSET_EMBED(copy);
ARY_SET_PTR(copy, ptr);
ARY_SET_LEN(copy, len);
ARY_SET_CAPA(copy, len);
// No allocation and exception expected that could leave `copy` in a
// bad state from the edits above.
ary_memcpy(copy, 0, len, RARRAY_CONST_PTR(orig));
}
/* Otherwise, orig is on heap and copy does not have enough space to embed
* the contents of orig. */
else {
VALUE shared_root = ary_make_shared(orig);
FL_UNSET_EMBED(copy);
ARY_SET_PTR(copy, ARY_HEAP_PTR(orig));
ARY_SET_LEN(copy, ARY_HEAP_LEN(orig));
rb_ary_set_shared(copy, shared_root);
}
ary_verify(copy);
return copy;
}
将 self 的元素替换为 other_array 的元素,other_array 必须是可转换为数组的对象;返回 self。
a = ['a', 'b', 'c'] # => ["a", "b", "c"] a.replace(['d', 'e']) # => ["d", "e"]
相关:请参阅 赋值的方法。
来源
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;
}
将给定的 objects 作为 self 的元素插入;返回 self。
当 index 为非负数时,在偏移量为 index 的元素之前插入 objects。
a = ['a', 'b', 'c'] # => ["a", "b", "c"] a.insert(1, :x, :y, :z) # => ["a", :x, :y, :z, "b", "c"]
如果 index 超出数组范围(index >= self.size),则扩展该数组。
a = ['a', 'b', 'c'] # => ["a", "b", "c"] a.insert(5, :x, :y, :z) # => ["a", "b", "c", nil, nil, :x, :y, :z]
当 index 为负数时,在偏移量为 index + self.size 的元素之后插入 objects。
a = ['a', 'b', 'c'] # => ["a", "b", "c"] a.insert(-2, :x, :y, :z) # => ["a", "b", :x, :y, :z, "c"]
如果没有给出 objects,则不执行任何操作。
a = ['a', 'b', 'c'] # => ["a", "b", "c"] a.insert(1) # => ["a", "b", "c"] a.insert(50) # => ["a", "b", "c"] a.insert(-50) # => ["a", "b", "c"]
如果给出了 objects 且 index 为负数且超出范围,则会引发 IndexError。
相关:请参阅 赋值的方法。
来源
static VALUE
rb_ary_inspect(VALUE ary)
{
if (RARRAY_LEN(ary) == 0) return rb_usascii_str_new2("[]");
return rb_exec_recursive(inspect_ary, ary, 0);
}
返回通过调用每个数组元素的 inspect 方法形成的新字符串。
a = [:foo, 'bar', 2] a.inspect # => "[:foo, \"bar\", 2]"
相关:请参阅 用于转换的方法。
来源
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;
}
返回 other_array 是否至少有一个元素 eql? 于 self 的某些元素。
[1, 2, 3].intersect?([3, 4, 5]) # => true [1, 2, 3].intersect?([4, 5, 6]) # => false
每个元素都必须正确实现方法 hash。
相关:请参阅 查询方法。
来源
static VALUE
rb_ary_intersection_multi(int argc, VALUE *argv, VALUE ary)
{
VALUE result = rb_ary_dup(ary);
int i;
for (i = 0; i < argc; i++) {
result = rb_ary_and(result, argv[i]);
}
return result;
}
返回一个新数组,其中包含 self 中 eql? 于给定的 other_arrays 中至少一个元素的每个元素;省略重复项。
[0, 0, 1, 1, 2, 3].intersection([0, 1, 2], [0, 1, 3]) # => [0, 1]
每个元素都必须正确实现方法 hash。
保留来自 self 的顺序。
[0, 1, 2].intersection([2, 1, 0]) # => [0, 1, 2]
如果没有给出任何参数,则返回 self 的副本。
相关:请参阅 合并的方法。
来源
static VALUE
rb_ary_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 元素形成的新字符串;对于每个元素 element:
-
如果
element是kind_of?(Array),则使用element.join(separator)递归转换。 -
否则,使用
element.to_s进行转换。
如果没有给出任何参数,则使用输出字段分隔符 $, 进行连接。
a = [:foo, 'bar', 2] $, # => nil a.join # => "foobar2"
如果给出了字符串参数 separator,则使用该分隔符进行连接。
a = [:foo, 'bar', 2] a.join("\n") # => "foo\nbar\n2"
递归连接嵌套数组。
a = [:foo, [:bar, [:baz, :bat]]] a.join # => "foobarbazbat"
相关:请参阅 用于转换的方法。
来源
static VALUE
rb_ary_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, :bam] a.keep_if {|element| element.to_s.start_with?('b') } # => ["bar", :bam]
如果没有给定代码块,则返回一个新的 Enumerator。
相关:请参阅 删除方法。
来源
# File array.rb, line 166 def last n = unspecified = true if Primitive.mandatory_only? Primitive.attr! :leaf Primitive.cexpr! %q{ ary_last(self) } else if unspecified Primitive.cexpr! %q{ ary_last(self) } else Primitive.cexpr! %q{ ary_take_first_or_last_n(self, NUM2LONG(n), ARY_TAKE_LAST) } end end end
从 self 返回元素,或者返回 nil;不会修改 self。
如果未给出任何参数,则返回最后一个元素,如果 self 为空,则返回 nil。
a = [:foo, 'bar', 2] a.last # => 2 a # => [:foo, "bar", 2] [].last # => nil
如果给定了非负整数参数 count,则返回一个新数组,其中包含 self 的后 count 个元素(如果可用)。
a = [:foo, 'bar', 2] a.last(2) # => ["bar", 2] a.last(50) # => [:foo, "bar", 2] a.last(0) # => [] [].last(3) # => []
相关:请参阅 获取的方法。
来源
static VALUE
rb_ary_length(VALUE ary)
{
long len = RARRAY_LEN(ary);
return LONG2NUM(len);
}
返回 self 中的元素计数。
[0, 1, 2].length # => 3 [].length # => 0
相关:请参阅 查询方法。
如果给定代码块,则对 self 的每个元素调用该代码块;返回一个新数组,其元素是该代码块的返回值。
a = [:foo, 'bar', 2] a1 = a.map {|element| element.class } a1 # => [Symbol, String, Integer]
如果没有给定代码块,则返回一个新的 Enumerator。
如果给定代码块,则对 self 的每个元素调用该代码块,并用该代码块的返回值替换该元素;返回 self。
a = [:foo, 'bar', 2] a.map! { |element| element.class } # => [Symbol, String, Integer]
如果没有给定代码块,则返回一个新的 Enumerator。
来源
static VALUE
rb_ary_max(int argc, VALUE *argv, VALUE ary)
{
VALUE result = Qundef, v;
VALUE num;
long i;
if (rb_check_arity(argc, 0, 1) && !NIL_P(num = argv[0]))
return rb_nmin_run(ary, num, 0, 1, 1);
const long n = RARRAY_LEN(ary);
if (rb_block_given_p()) {
for (i = 0; i < RARRAY_LEN(ary); i++) {
v = RARRAY_AREF(ary, i);
if (UNDEF_P(result) || rb_cmpint(rb_yield_values(2, v, result), v, result) > 0) {
result = v;
}
}
}
else if (n > 0) {
result = RARRAY_AREF(ary, 0);
if (n > 1) {
if (FIXNUM_P(result) && CMP_OPTIMIZABLE(INTEGER)) {
return ary_max_opt_fixnum(ary, 1, result);
}
else if (STRING_P(result) && CMP_OPTIMIZABLE(STRING)) {
return ary_max_opt_string(ary, 1, result);
}
else if (RB_FLOAT_TYPE_P(result) && CMP_OPTIMIZABLE(FLOAT)) {
return ary_max_opt_float(ary, 1, result);
}
else {
return ary_max_generic(ary, 1, result);
}
}
}
if (UNDEF_P(result)) return Qnil;
return result;
}
返回以下之一:
-
来自
self的最大值元素。 -
来自
self的最大值元素的新数组。
不修改 self。
如果没有给出代码块,则 self 中的每个元素都必须使用数值响应方法 <=>。
如果没有参数且没有代码块,则返回 self 中每个方法 <=> 具有最大值的元素。
[1, 0, 3, 2].max # => 3
如果使用了非负数值参数 count 并且没有代码块,则返回一个新数组,其中最多包含 count 个元素(按降序排列,每个方法 <=>)。
[1, 0, 3, 2].max(3) # => [3, 2, 1] [1, 0, 3, 2].max(3.0) # => [3, 2, 1] [1, 0, 3, 2].max(9) # => [3, 2, 1, 0] [1, 0, 3, 2].max(0) # => []
如果给出了代码块,则该代码块必须返回数值。
如果使用了代码块且没有参数,则调用代码块 self.size - 1 次来比较元素;返回每个代码块具有最大值的元素。
['0', '', '000', '00'].max {|a, b| a.size <=> b.size } # => "000"
如果使用了非负数值参数 count 和代码块,则返回一个新数组,其中最多包含 count 个元素(按降序排列,每个代码块)。
['0', '', '000', '00'].max(2) {|a, b| a.size <=> b.size } # => ["000", "00"]
相关:请参阅 获取的方法。
来源
static VALUE
rb_ary_min(int argc, VALUE *argv, VALUE ary)
{
VALUE result = Qundef, v;
VALUE num;
long i;
if (rb_check_arity(argc, 0, 1) && !NIL_P(num = argv[0]))
return rb_nmin_run(ary, num, 0, 0, 1);
const long n = RARRAY_LEN(ary);
if (rb_block_given_p()) {
for (i = 0; i < RARRAY_LEN(ary); i++) {
v = RARRAY_AREF(ary, i);
if (UNDEF_P(result) || rb_cmpint(rb_yield_values(2, v, result), v, result) < 0) {
result = v;
}
}
}
else if (n > 0) {
result = RARRAY_AREF(ary, 0);
if (n > 1) {
if (FIXNUM_P(result) && CMP_OPTIMIZABLE(INTEGER)) {
return ary_min_opt_fixnum(ary, 1, result);
}
else if (STRING_P(result) && CMP_OPTIMIZABLE(STRING)) {
return ary_min_opt_string(ary, 1, result);
}
else if (RB_FLOAT_TYPE_P(result) && CMP_OPTIMIZABLE(FLOAT)) {
return ary_min_opt_float(ary, 1, result);
}
else {
return ary_min_generic(ary, 1, result);
}
}
}
if (UNDEF_P(result)) return Qnil;
return result;
}
返回以下之一:
-
来自
self的最小值元素。 -
来自
self的最小值元素的新数组。
不修改 self。
如果没有给出代码块,则 self 中的每个元素都必须使用数值响应方法 <=>。
不带参数且不带代码块时,返回 self 中根据方法 <=> 比较得出的最小值元素。
[1, 0, 3, 2].min # => 0
带有非负数值参数 count 且不带代码块时,返回一个新数组,其中包含最多 count 个元素,并按照方法 <=> 升序排列。
[1, 0, 3, 2].min(3) # => [0, 1, 2] [1, 0, 3, 2].min(3.0) # => [0, 1, 2] [1, 0, 3, 2].min(9) # => [0, 1, 2, 3] [1, 0, 3, 2].min(0) # => []
如果给出了代码块,则该代码块必须返回数值。
带有代码块且不带参数时,调用代码块 self.size - 1 次来比较元素;返回根据代码块比较得出的最小值元素。
['0', '', '000', '00'].min {|a, b| a.size <=> b.size } # => ""
带有非负数值参数 count 和代码块时,返回一个新数组,其中包含最多 count 个元素,并按照代码块比较升序排列。
['0', '', '000', '00'].min(2) {|a, b| a.size <=> b.size } # => ["", "0"]
相关:请参阅 获取的方法。
来源
static VALUE
rb_ary_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));
}
返回一个包含 2 个元素的数组,其中包含 self 中的最小值和最大值元素;不会修改 self。
如果不提供代码块,则使用方法 <=> 确定最小值和最大值。
[1, 0, 3, 2].minmax # => [0, 3]
如果提供了代码块,则代码块必须返回一个数值;代码块将被调用 self.size - 1 次以比较元素;返回根据代码块比较得出的最小值和最大值元素。
['0', '', '000', '00'].minmax {|a, b| a.size <=> b.size } # => ["", "000"]
相关:请参阅 获取的方法。
来源
static VALUE
rb_ary_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,否则返回 false。
如果没有提供代码块和参数,如果 self 没有真值元素,则返回 true,否则返回 false。
[nil, false].none? # => true [nil, 0, false].none? # => false [].none? # => true
如果提供了参数 object,如果存在任何元素 element 满足 object === element,则返回 false;否则返回 true。
['food', 'drink'].none?(/bar/) # => true ['food', 'drink'].none?(/foo/) # => false [].none?(/foo/) # => true [0, 1, 2].none?(3) # => true [0, 1, 2].none?(1) # => false
如果提供了代码块,则使用 self 中的每个元素调用代码块;如果代码块没有返回真值,则返回 true,否则返回 false。
[0, 1, 2].none? {|element| element > 3 } # => true [0, 1, 2].none? {|element| element > 1 } # => false
相关:请参阅 查询方法。
来源
static VALUE
rb_ary_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 中恰好有一个元素满足给定条件,则返回 true。
如果没有提供代码块和参数,如果 self 中恰好有一个真值元素,则返回 true,否则返回 false。
[nil, 0].one? # => true [0, 0].one? # => false [nil, nil].one? # => false [].one? # => false
如果提供了代码块,则使用 self 中的每个元素调用代码块;如果代码块恰好为一个元素返回真值,则返回 true,否则返回 false。
[0, 1, 2].one? {|element| element > 0 } # => false [0, 1, 2].one? {|element| element > 1 } # => true [0, 1, 2].one? {|element| element > 2 } # => false
如果提供了参数 object,如果恰好有一个元素 element 满足 object === element,则返回 true;否则返回 false。
[0, 1, 2].one?(0) # => true [0, 0, 1].one?(0) # => false [1, 1, 2].one?(0) # => false ['food', 'drink'].one?(/bar/) # => false ['food', 'drink'].one?(/foo/) # => true [].one?(/foo/) # => false
相关:请参阅 查询方法。
来源
# File pack.rb, line 7 def pack(fmt, buffer: nil) Primitive.pack_pack(fmt, buffer) end
将 self 中的每个元素格式化为一个二进制字符串;返回该字符串。请参阅打包数据。
来源
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 的元素的排列;排列的顺序是不确定的。
如果提供了代码块和范围内的正整数参数 count (0 < count <= self.size),则使用 self 的每个大小为 count 的排列调用代码块;返回 self
a = [0, 1, 2] perms = [] a.permutation(1) {|perm| perms.push(perm) } perms # => [[0], [1], [2]] perms = [] a.permutation(2) {|perm| perms.push(perm) } perms # => [[0, 1], [0, 2], [1, 0], [1, 2], [2, 0], [2, 1]] perms = [] a.permutation(3) {|perm| perms.push(perm) } perms # => [[0, 1, 2], [0, 2, 1], [1, 0, 2], [1, 2, 0], [2, 0, 1], [2, 1, 0]]
当 count 为零时,使用一个新的空数组调用该代码块一次。
perms = [] a.permutation(0) {|perm| perms.push(perm) } perms # => [[]]
当 count 超出范围(负数或大于 self.size)时,不调用代码块
a.permutation(-1) {|permutation| fail 'Cannot happen' } a.permutation(4) {|permutation| fail 'Cannot happen' }
如果没有给定代码块,则返回一个新的 Enumerator。
相关:用于迭代的方法。
来源
static VALUE
rb_ary_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 的末尾元素。
如果没有提供参数,则移除并返回最后一个元素(如果可用);否则返回 nil
a = [:foo, 'bar', 2] a.pop # => 2 a # => [:foo, "bar"] [].pop # => nil
如果给定了非负整数参数 count,则返回一个新数组,其中包含 self 的后 count 个元素(如果可用)。
a = [:foo, 'bar', 2] a.pop(2) # => ["bar", 2] a # => [:foo] a = [:foo, 'bar', 2] a.pop(50) # => [:foo, "bar", 2] a # => []
相关:Array#push;另请参阅用于删除的方法。
将给定的 objects 前置到 self
a = [:foo, 'bar', 2] a.unshift(:bam, :bat) # => [:bam, :bat, :foo, "bar", 2]
相关:Array#shift;另请参阅用于赋值的方法。
来源
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;
}
计算所有数组(包括 self 和 other_arrays)中元素的所有组合
-
组合的数量是所有数组(包括
self和other_arrays)大小的乘积。 -
返回的组合的顺序是不确定的。
如果没有提供代码块,则将组合作为数组的数组返回
p = [0, 1].product([2, 3]) # => [[0, 2], [0, 3], [1, 2], [1, 3]] p.size # => 4 p = [0, 1].product([2, 3], [4, 5]) # => [[0, 2, 4], [0, 2, 5], [0, 3, 4], [0, 3, 5], [1, 2, 4], [1, 2, 5], [1, 3, 4], [1, 3,... p.size # => 8
如果 self 或任何参数为空,则返回一个空数组
[].product([2, 3], [4, 5]) # => [] [0, 1].product([2, 3], []) # => []
如果没有提供参数,则返回一个包含 1 个元素的数组的数组,每个数组包含 self 的一个元素
a.product # => [[0], [1], [2]]
如果提供了代码块,则使用每个组合调用代码块;返回 self
p = [] [0, 1].product([2, 3]) {|combination| p.push(combination) } p # => [[0, 2], [0, 3], [1, 2], [1, 3]]
如果 self 或任何参数为空,则不调用代码块
[].product([2, 3], [4, 5]) {|combination| fail 'Cannot happen' } # => [] [0, 1].product([2, 3], []) {|combination| fail 'Cannot happen' } # => [0, 1]
如果没有提供参数,则使用 self 的每个元素(作为包含 1 个元素的数组)调用代码块
p = [] [0, 1].product {|combination| p.push(combination) } p # => [[0], [1]]
相关:请参阅 合并的方法。
来源
static VALUE
rb_ary_push_m(int argc, VALUE *argv, VALUE ary)
{
return rb_ary_cat(ary, argv, argc);
}
将 objects 中的每个参数追加到 self;返回 self。
a = [:foo, 'bar', 2] # => [:foo, "bar", 2] a.push(:baz, :bat) # => [:foo, "bar", 2, :baz, :bat]
将每个参数作为单个元素追加,即使它是另一个数组。
a = [:foo, 'bar', 2] # => [:foo, "bar", 2] a.push([:baz, :bat], [:bam, :bad]) # => [:foo, "bar", 2, [:baz, :bat], [:bam, :bad]]
相关:请参阅 赋值的方法。
来源
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 中的第一个元素 ele,使得 ele 是一个数组且 ele[1] == object
a = [{foo: 0}, [2, 4], [4, 5, 6], [4, 5]] a.rassoc(4) # => [2, 4] a.rassoc(5) # => [4, 5, 6]
如果未找到此类元素,则返回 nil。
相关:Array#assoc;另请参阅用于获取的方法。
来源
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 中代码块返回 false 或 nil 的所有元素
a = [:foo, 'bar', 2, 'bat'] a1 = a.reject {|element| element.to_s.start_with?('b') } a1 # => [:foo, 2]
如果没有给定代码块,则返回一个新的 Enumerator。
相关:用于获取的方法。
来源
static VALUE
rb_ary_reject_bang(VALUE ary)
{
RETURN_SIZED_ENUMERATOR(ary, 0, 0, ary_enum_length);
rb_ary_modify(ary);
return ary_reject_bang(ary);
}
如果提供了代码块,则使用 self 的每个元素调用代码块;移除代码块返回真值的每个元素。
如果移除任何元素,则返回 self
a = [:foo, 'bar', 2, 'bat'] a.reject! {|element| element.to_s.start_with?('b') } # => [:foo, 2]
如果没有移除元素,则返回 nil。
如果没有给定代码块,则返回一个新的 Enumerator。
相关:请参阅 删除方法。
来源
static VALUE
rb_ary_repeated_combination(VALUE ary, VALUE num)
{
long n, i, len;
n = NUM2LONG(num); /* Combination size from argument */
RETURN_SIZED_ENUMERATOR(ary, 1, &num, rb_ary_repeated_combination_size); /* Return enumerator if no block */
len = RARRAY_LEN(ary);
if (n < 0) {
/* yield nothing */
}
else if (n == 0) {
rb_yield(rb_ary_new2(0));
}
else if (n == 1) {
for (i = 0; i < RARRAY_LEN(ary); i++) {
rb_yield(rb_ary_new3(1, RARRAY_AREF(ary, i)));
}
}
else if (len == 0) {
/* yield nothing */
}
else {
volatile VALUE t0;
long *p = ALLOCV_N(long, t0, n);
VALUE ary0 = ary_make_shared_copy(ary); /* private defensive copy of ary */
RBASIC_CLEAR_CLASS(ary0);
rcombinate0(len, n, p, n, ary0); /* compute and yield repeated combinations */
ALLOCV_END(t0);
RBASIC_SET_CLASS_RAW(ary0, rb_cArray);
}
return ary;
}
如果提供了代码块,则使用 self 的元素的每个长度为 size 的重复组合调用代码块;每个组合都是一个数组;返回 self。组合的顺序是不确定的。
如果提供了正整数参数 size,则使用 self 的元素的每个 size 元组重复组合调用代码块。组合的数量为 (size+1)(size+2)/2。
示例
-
size为 1c = [] [0, 1, 2].repeated_combination(1) {|combination| c.push(combination) } c # => [[0], [1], [2]]
-
size为 2c = [] [0, 1, 2].repeated_combination(2) {|combination| c.push(combination) } c # => [[0, 0], [0, 1], [0, 2], [1, 1], [1, 2], [2, 2]]
如果 size 为零,则使用一个空数组调用代码块一次。
如果 size 为负数,则不调用代码块
[0, 1, 2].repeated_combination(-1) {|combination| fail 'Cannot happen' }
如果没有给定代码块,则返回一个新的 Enumerator。
相关:请参阅 合并的方法。
来源
static VALUE
rb_ary_repeated_permutation(VALUE ary, VALUE num)
{
long r, n, i;
n = RARRAY_LEN(ary); /* Array length */
RETURN_SIZED_ENUMERATOR(ary, 1, &num, rb_ary_repeated_permutation_size); /* Return Enumerator if no block */
r = NUM2LONG(num); /* Permutation size from argument */
if (r < 0) {
/* no permutations: yield nothing */
}
else if (r == 0) { /* exactly one permutation: the zero-length array */
rb_yield(rb_ary_new2(0));
}
else if (r == 1) { /* this is a special, easy case */
for (i = 0; i < RARRAY_LEN(ary); i++) {
rb_yield(rb_ary_new3(1, RARRAY_AREF(ary, i)));
}
}
else { /* this is the general case */
volatile VALUE t0;
long *p = ALLOCV_N(long, t0, r);
VALUE ary0 = ary_make_shared_copy(ary); /* private defensive copy of ary */
RBASIC_CLEAR_CLASS(ary0);
rpermute0(n, r, p, ary0); /* compute and yield repeated permutations */
ALLOCV_END(t0);
RBASIC_SET_CLASS_RAW(ary0, rb_cArray);
}
return ary;
}
如果提供了代码块,则使用 self 的元素的每个长度为 size 的重复排列调用代码块;每个排列都是一个数组;返回 self。排列的顺序是不确定的。
如果提供了正整数参数 size,则使用 self 的元素的每个 size 元组重复排列调用代码块。排列的数量为 self.size**size。
示例
-
size为 1p = [] [0, 1, 2].repeated_permutation(1) {|permutation| p.push(permutation) } p # => [[0], [1], [2]]
-
size为 2p = [] [0, 1, 2].repeated_permutation(2) {|permutation| p.push(permutation) } p # => [[0, 0], [0, 1], [0, 2], [1, 0], [1, 1], [1, 2], [2, 0], [2, 1], [2, 2]]
如果 size 为零,则使用一个空数组调用代码块一次。
如果 size 为负数,则不调用代码块
[0, 1, 2].repeated_permutation(-1) {|permutation| fail 'Cannot happen' }
如果没有给定代码块,则返回一个新的 Enumerator。
相关:请参阅 合并的方法。
来源
static VALUE
rb_ary_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 的元素,顺序相反
[0, 1, 2].reverse # => [2, 1, 0]
相关:请参阅 合并的方法。
来源
static VALUE
rb_ary_reverse_bang(VALUE ary)
{
return rb_ary_reverse(ary);
}
反转 self 的元素的顺序;返回 self
a = [0, 1, 2] a.reverse! # => [2, 1, 0] a # => [2, 1, 0]
相关:请参阅 赋值的方法。
来源
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;
}
当提供代码块时,向后遍历 self 的元素,以相反的顺序将每个元素传递给代码块;返回 self
a = [] [0, 1, 2].reverse_each {|element| a.push(element) } a # => [2, 1, 0]
允许在迭代期间修改数组。
a = ['a', 'b', 'c'] a.reverse_each {|element| a.clear if element.start_with?('b') } a # => []
当没有提供代码块时,返回一个新的Enumerator。
相关:请参阅 迭代方法。
来源
static VALUE
rb_ary_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;
}
返回最后一个元素 object == element 的索引。
如果提供了参数 object,则返回找到的最后一个此类元素的索引
a = [:foo, 'bar', 2, 'bar'] a.rindex('bar') # => 3
如果未找到此类对象,则返回 nil。
如果提供了代码块,则使用每个连续的元素调用代码块;返回代码块返回真值的最后一个元素的索引
a = [:foo, 'bar', 2, 'bar'] a.rindex {|element| element == 'bar' } # => 3
如果代码块从未返回真值,则返回 nil。
当没有提供参数或代码块时,返回一个新的Enumerator。
相关:请参阅 查询方法。
来源
static VALUE
rb_ary_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 形成的新的数组,其中元素从一端旋转到另一端。
如果为非负数值 count,则将元素从开头旋转到结尾
[0, 1, 2, 3].rotate(2) # => [2, 3, 0, 1] [0, 1, 2, 3].rotate(2.1) # => [2, 3, 0, 1]
如果 count 很大,则使用 count % array.size 作为计数
[0, 1, 2, 3].rotate(22) # => [2, 3, 0, 1]
如果 count 为零,则不旋转元素
[0, 1, 2, 3].rotate(0) # => [0, 1, 2, 3]
如果为负数值 count,则以相反的方向旋转,从结尾到开头
[0, 1, 2, 3].rotate(-1) # => [3, 0, 1, 2]
如果 count 很小(远离零),则使用 count % array.size 作为计数
[0, 1, 2, 3].rotate(-21) # => [3, 0, 1, 2]
相关:请参阅 获取的方法。
来源
static VALUE
rb_ary_rotate_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。
如果为非负数值 count,则将 count 个元素从开头旋转到结尾
[0, 1, 2, 3].rotate!(2) # => [2, 3, 0, 1] [0, 1, 2, 3].rotate!(2.1) # => [2, 3, 0, 1]
如果 count 很大,则使用 count % array.size 作为计数
[0, 1, 2, 3].rotate!(21) # => [1, 2, 3, 0]
如果 count 为零,则不旋转元素
[0, 1, 2, 3].rotate!(0) # => [0, 1, 2, 3]
如果为负数值 count,则以相反的方向旋转,从结尾到开头
[0, 1, 2, 3].rotate!(-1) # => [3, 0, 1, 2]
如果 count 很小(远离零),则使用 count % array.size 作为计数
[0, 1, 2, 3].rotate!(-21) # => [3, 0, 1, 2]
相关:请参阅 赋值的方法。
来源
# File array.rb, line 95 def sample(n = (ary = false), random: Random) if Primitive.mandatory_only? # Primitive.cexpr! %{ rb_ary_sample(self, rb_cRandom, Qfalse, Qfalse) } Primitive.ary_sample0 else # Primitive.cexpr! %{ rb_ary_sample(self, random, n, ary) } Primitive.ary_sample(random, n, ary) end end
返回 self 中的随机元素,由关键字参数 random 给出的对象选择。
如果没有提供参数 count,则返回 self 中的一个随机元素
a = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] a.sample # => 3 a.sample # => 8
如果 self 为空,则返回 nil
[].sample # => nil
如果提供了非负数值参数 count,则返回一个包含来自 self 的 count 个随机元素的新数组
a.sample(3) # => [8, 9, 2] a.sample(6) # => [9, 6, 0, 3, 1, 4]
结果数组的顺序与 self 的顺序无关。
如果 self 为空,则返回一个新的空Array
[].sample(4) # => []
可能会在 self 中返回重复项
a = [1, 1, 1, 2, 2, 3] a.sample(a.size) # => [1, 1, 3, 2, 1, 2]
返回的元素不超过 a.size 个(因为不引入新的重复项)
a.sample(50) # => [6, 4, 1, 8, 5, 9, 0, 2, 3, 7]
使用关键字参数 random 给出的对象作为随机数生成器
a = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] a.sample(random: Random.new(1)) # => 6 a.sample(4, random: Random.new(1)) # => [6, 10, 9, 2]
相关:请参阅 获取的方法。
来源
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 中代码块返回真值的那些元素。
a = [:foo, 'bar', 2, :bam] a.select {|element| element.to_s.start_with?('b') } # => ["bar", :bam]
如果没有给定代码块,则返回一个新的 Enumerator。
相关:请参阅 获取的方法。
来源
static VALUE
rb_ary_select_bang(VALUE ary)
{
struct select_bang_arg args;
RETURN_SIZED_ENUMERATOR(ary, 0, 0, ary_enum_length);
rb_ary_modify(ary);
args.ary = ary;
args.len[0] = args.len[1] = 0;
return rb_ensure(select_bang_i, (VALUE)&args, select_bang_ensure, (VALUE)&args);
}
如果给定了代码块,则使用 self 的每个元素调用该代码块;从 self 中删除代码块返回 false 或 nil 的那些元素。
如果删除了任何元素,则返回 self。
a = [:foo, 'bar', 2, :bam] a.select! {|element| element.to_s.start_with?('b') } # => ["bar", :bam]
如果没有删除任何元素,则返回 nil。
如果没有给定代码块,则返回一个新的 Enumerator。
相关:请参阅 删除方法。
来源
# File lib/shellwords.rb, line 251 def shelljoin Shellwords.join(self) end
从参数列表 array 构建命令行字符串,将所有元素转义以用于 Bourne shell,并用空格分隔。
有关详细信息,请参阅Shellwords.shelljoin。
来源
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 中移除并返回头部元素。
如果没有参数,则移除并返回一个元素(如果可用),否则返回 nil
a = [0, 1, 2, 3] a.shift # => 0 a # => [1, 2, 3] [].shift # => nil
如果提供了非负数值参数 count,则移除并返回前 count 个元素
a = [0, 1, 2, 3] a.shift(2) # => [0, 1] a # => [2, 3] a.shift(1.1) # => [2] a # => [3] a.shift(0) # => [] a # => [3]
如果 count 很大,则移除并返回所有元素
a = [0, 1, 2, 3] a.shift(50) # => [0, 1, 2, 3] a # => []
如果 self 为空,则返回一个新的空数组。
相关:请参阅 删除方法。
来源
# File array.rb, line 45 def shuffle(random: Random) Primitive.rb_ary_shuffle(random) end
返回一个新数组,其中包含 self 中的所有元素,顺序随机,由关键字参数 random 给出的对象选择
a = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] a.shuffle # => [0, 8, 1, 9, 6, 3, 4, 7, 2, 5] a.shuffle # => [8, 9, 0, 5, 1, 2, 6, 4, 7, 3]
包含重复的元素
a = [0, 1, 0, 1, 0, 1, 0, 1, 0, 1] a.shuffle # => [1, 0, 1, 1, 0, 0, 1, 0, 0, 1] a.shuffle # => [1, 1, 0, 0, 0, 1, 1, 0, 0, 1]
使用关键字参数 random 给出的对象作为随机数生成器。
相关:请参阅 获取的方法。
来源
# File array.rb, line 22 def shuffle!(random: Random) Primitive.rb_ary_shuffle_bang(random) end
将 self 中的所有元素洗牌为随机顺序,由关键字参数 random 给出的对象选择。返回 self
a = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] a.shuffle! # => [5, 3, 8, 7, 6, 1, 9, 4, 2, 0] a.shuffle! # => [9, 4, 0, 6, 2, 8, 1, 5, 3, 7]
包含重复的元素
a = [0, 1, 0, 1, 0, 1, 0, 1, 0, 1] a.shuffle! # => [1, 0, 0, 1, 1, 0, 1, 0, 0, 1] a.shuffle! # => [0, 1, 0, 1, 1, 0, 1, 0, 1, 0]
使用关键字参数 random 给出的对象作为随机数生成器。
相关:请参阅 赋值的方法。
从 self 返回元素;不修改 self。
简而言之
a = [:foo, 'bar', 2] # Single argument index: returns one element. a[0] # => :foo # Zero-based index. a[-1] # => 2 # Negative index counts backwards from end. # Arguments start and length: returns an array. a[1, 2] # => ["bar", 2] a[-2, 2] # => ["bar", 2] # Negative start counts backwards from end. # Single argument range: returns an array. a[0..1] # => [:foo, "bar"] a[0..-2] # => [:foo, "bar"] # Negative range-begin counts backwards from end. a[-2..2] # => ["bar", 2] # Negative range-end counts backwards from end.
当给出单个整数参数 index 时,返回偏移量为 index 的元素
a = [:foo, 'bar', 2] a[0] # => :foo a[2] # => 2 a # => [:foo, "bar", 2]
如果 index 为负数,则从 self 的末尾向后计数
a = [:foo, 'bar', 2] a[-1] # => 2 a[-2] # => "bar"
如果 index 超出范围,则返回 nil。
当给出两个 Integer 参数 start 和 length 时,返回一个大小为 length 的新 Array,其中包含从偏移量 start 开始的连续元素
a = [:foo, 'bar', 2] a[0, 2] # => [:foo, "bar"] a[1, 2] # => ["bar", 2]
如果 start + length 大于 self.length,则返回从偏移量 start 到末尾的所有元素
a = [:foo, 'bar', 2] a[0, 4] # => [:foo, "bar", 2] a[1, 3] # => ["bar", 2] a[2, 2] # => [2]
如果 start == self.size 且 length >= 0,则返回一个新的空 Array。
如果 length 为负数,则返回 nil。
当给出单个 Range 参数 range 时,将 range.min 视为上面的 start,将 range.size 视为上面的 length
a = [:foo, 'bar', 2] a[0..1] # => [:foo, "bar"] a[1..2] # => ["bar", 2]
特殊情况:如果 range.start == a.size,则返回一个新的空 Array。
如果 range.end 为负数,则从末尾计算结束索引
a = [:foo, 'bar', 2] a[0..-1] # => [:foo, "bar", 2] a[0..-2] # => [:foo, "bar"] a[0..-3] # => [:foo]
如果 range.start 为负数,则从末尾计算开始索引
a = [:foo, 'bar', 2] a[-1..2] # => [2] a[-2..2] # => ["bar", 2] a[-3..2] # => [:foo, "bar", 2]
如果 range.start 大于数组大小,则返回 nil。
a = [:foo, 'bar', 2] a[4..1] # => nil a[4..0] # => nil a[4..-1] # => nil
当给出单个 Enumerator::ArithmeticSequence 参数 aseq 时,返回一个与序列生成的索引对应的元素的 Array。
a = ['--', 'data1', '--', 'data2', '--', 'data3'] a[(1..).step(2)] # => ["data1", "data2", "data3"]
与使用范围切片不同,如果算术序列的开始或结束大于数组大小,则抛出 RangeError。
a = ['--', 'data1', '--', 'data2', '--', 'data3'] a[(1..11).step(2)] # RangeError (((1..11).step(2)) out of range) a[(7..).step(2)] # RangeError (((7..).step(2)) out of range)
如果给出了单个参数,并且其类型不是列出的类型之一,则尝试将其转换为 Integer,如果无法转换,则引发错误
a = [:foo, 'bar', 2] # Raises TypeError (no implicit conversion of Symbol into Integer): a[:foo]
相关:请参阅 获取的方法。
来源
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 中移除并返回元素。
当给定数值参数 index 时,移除并返回偏移量为 index 的元素
a = ['a', 'b', 'c', 'd'] a.slice!(2) # => "c" a # => ["a", "b", "d"] a.slice!(2.1) # => "d" a # => ["a", "b"]
如果 index 为负数,则从 self 的末尾向后计数
a = ['a', 'b', 'c', 'd'] a.slice!(-2) # => "c" a # => ["a", "b", "d"]
如果 index 超出范围,则返回 nil。
当给定数值参数 start 和 length 时,从 self 中移除从基于零的偏移量 start 开始的 length 个元素;返回被移除的对象到一个新数组中
a = ['a', 'b', 'c', 'd'] a.slice!(1, 2) # => ["b", "c"] a # => ["a", "d"] a.slice!(0.1, 1.1) # => ["a"] a # => ["d"]
如果 start 为负数,则从 self 的末尾向后计数。
a = ['a', 'b', 'c', 'd'] a.slice!(-2, 1) # => ["c"] a # => ["a", "b", "d"]
如果 start 超出范围,则返回 nil
a = ['a', 'b', 'c', 'd'] a.slice!(5, 1) # => nil a.slice!(-5, 1) # => nil
如果 start + length 超出数组大小,则移除并返回从偏移量 start 到末尾的所有元素
a = ['a', 'b', 'c', 'd'] a.slice!(2, 50) # => ["c", "d"] a # => ["a", "b"]
如果 start == a.size 且 length 为非负数,则返回一个新的空数组。
如果 length 为负数,则返回 nil。
当给定 Range 参数 range 时,将 range.min 视为 start(如上所述),将 range.size 视为 length(如上所述)
a = ['a', 'b', 'c', 'd'] a.slice!(1..2) # => ["b", "c"] a # => ["a", "d"]
如果 range.start == a.size,则返回一个新的空数组
a = ['a', 'b', 'c', 'd'] a.slice!(4..5) # => []
如果 range.start 大于数组大小,则返回 nil
a = ['a', 'b', 'c', 'd'] a.slice!(5..6) # => nil
如果 range.start 为负数,则通过从 self 末尾倒数来计算起始索引
a = ['a', 'b', 'c', 'd'] a.slice!(-2..2) # => ["c"]
如果 range.end 为负数,则通过从 self 末尾倒数来计算结束索引
a = ['a', 'b', 'c', 'd'] a.slice!(0..-2) # => ["a", "b", "c"]
相关:请参阅 删除方法。
来源
VALUE
rb_ary_sort(VALUE ary)
{
ary = rb_ary_dup(ary);
rb_ary_sort_bang(ary);
return ary;
}
返回一个包含 self 元素的排序后的新数组。
如果没有给出块,则使用运算符 <=> 比较元素(参见 Object#<=>)
[0, 2, 3, 1].sort # => [0, 1, 2, 3]
如果给出了块,则使用 self 中每对元素的组合来调用该块;对于每一对 a 和 b,该块应返回一个数值
-
当
b应该在a之后时为负数。 -
当
a和b相等时为零。 -
当
a应该在b之后时为正数。
示例
a = [3, 2, 0, 1] a.sort {|a, b| a <=> b } # => [0, 1, 2, 3] a.sort {|a, b| b <=> a } # => [3, 2, 1, 0]
当块返回零时,a 和 b 的顺序是不确定的,并且可能是不稳定的。
相关:请参阅 获取的方法。
来源
VALUE
rb_ary_sort_bang(VALUE ary)
{
rb_ary_modify(ary);
RUBY_ASSERT(!ARY_SHARED_P(ary));
if (RARRAY_LEN(ary) > 1) {
VALUE tmp = ary_make_substitution(ary); /* only ary refers tmp */
struct ary_sort_data data;
long len = RARRAY_LEN(ary);
RBASIC_CLEAR_CLASS(tmp);
data.ary = tmp;
data.receiver = ary;
RARRAY_PTR_USE(tmp, ptr, {
ruby_qsort(ptr, len, sizeof(VALUE),
rb_block_given_p()?sort_1:sort_2, &data);
}); /* WB: no new reference */
rb_ary_modify(ary);
if (ARY_EMBED_P(tmp)) {
if (ARY_SHARED_P(ary)) { /* ary might be destructively operated in the given block */
rb_ary_unshare(ary);
FL_SET_EMBED(ary);
}
if (ARY_EMBED_LEN(tmp) > ARY_CAPA(ary)) {
ary_resize_capa(ary, ARY_EMBED_LEN(tmp));
}
ary_memcpy(ary, 0, ARY_EMBED_LEN(tmp), ARY_EMBED_PTR(tmp));
ARY_SET_LEN(ary, ARY_EMBED_LEN(tmp));
}
else {
if (!ARY_EMBED_P(ary) && ARY_HEAP_PTR(ary) == ARY_HEAP_PTR(tmp)) {
FL_UNSET_SHARED(ary);
ARY_SET_CAPA(ary, RARRAY_LEN(tmp));
}
else {
RUBY_ASSERT(!ARY_SHARED_P(tmp));
if (ARY_EMBED_P(ary)) {
FL_UNSET_EMBED(ary);
}
else if (ARY_SHARED_P(ary)) {
/* ary might be destructively operated in the given block */
rb_ary_unshare(ary);
}
else {
ary_heap_free(ary);
}
ARY_SET_PTR(ary, ARY_HEAP_PTR(tmp));
ARY_SET_HEAP_LEN(ary, len);
ARY_SET_CAPA(ary, ARY_HEAP_LEN(tmp));
}
/* tmp was lost ownership for the ptr */
FL_UNSET(tmp, FL_FREEZE);
FL_SET_EMBED(tmp);
ARY_SET_EMBED_LEN(tmp, 0);
FL_SET(tmp, FL_FREEZE);
}
/* tmp will be GC'ed. */
RBASIC_SET_CLASS_RAW(tmp, rb_cArray); /* rb_cArray must be marked */
}
ary_verify(ary);
return ary;
}
类似于 Array#sort,但返回 self,其元素在原地排序。
相关:请参阅 赋值的方法。
来源
static VALUE
rb_ary_sort_by_bang(VALUE ary)
{
VALUE sorted;
RETURN_SIZED_ENUMERATOR(ary, 0, 0, ary_enum_length);
rb_ary_modify(ary);
sorted = rb_block_call(ary, rb_intern("sort_by"), 0, 0, sort_by_i, 0);
rb_ary_replace(ary, sorted);
return ary;
}
如果给出了块,则在原地对 self 的元素进行排序;返回 self。
使用每个连续的元素调用该块;根据该块返回的值对元素进行排序
a = ['aaaa', 'bbb', 'cc', 'd'] a.sort_by! {|element| element.size } a # => ["d", "cc", "bbb", "aaaa"]
对于该块返回的重复值,顺序是不确定的,并且可能是不稳定的。
如果没有给定代码块,则返回一个新的 Enumerator。
相关:请参阅 赋值的方法。
来源
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;
}
如果没有给出块,则返回 init 和 self 的所有元素之和;对于数组 array 和值 init,等效于
sum = init array.each {|element| sum += element } sum
例如,[e0, e1, e2].sum 返回 init + e0 + e1 + e2。
示例
[0, 1, 2, 3].sum # => 6 [0, 1, 2, 3].sum(100) # => 106 ['abc', 'def', 'ghi'].sum('jkl') # => "jklabcdefghi" [[:foo, :bar], ['foo', 'bar']].sum([2, 3]) # => [2, 3, :foo, :bar, "foo", "bar"]
init 值和元素不需要是数值,但必须全部与 + 兼容
# Raises TypeError: Array can't be coerced into Integer. [[:foo, :bar], ['foo', 'bar']].sum(2)
如果给出了块,则使用 self 的每个元素调用该块;该块的返回值(而不是元素本身)用作被加数
['zero', 1, :two].sum('Coerced and concatenated: ') {|element| element.to_s } # => "Coerced and concatenated: zero1two"
注意
-
对于字符串数组或数组的数组,
Array#join和Array#flatten可能比Array#sum更快。
来源
static VALUE
rb_ary_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 的前 count 个元素的新数组(如果可用);count 必须是非负数值;不修改 self
a = ['a', 'b', 'c', 'd'] a.take(2) # => ["a", "b"] a.take(2.1) # => ["a", "b"] a.take(50) # => ["a", "b", "c", "d"] a.take(0) # => []
相关:请参阅 获取的方法。
来源
static VALUE
rb_ary_take_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 的每个连续元素调用该块;如果该块返回 false 或 nil,则停止迭代;返回一个包含该块返回真值的所有元素的新数组
a = [0, 1, 2, 3, 4, 5] a.take_while {|element| element < 3 } # => [0, 1, 2] a.take_while {|element| true } # => [0, 1, 2, 3, 4, 5] a.take_while {|element| false } # => []
如果没有给定代码块,则返回一个新的 Enumerator。
不修改 self。
相关:请参阅 获取的方法。
来源
static VALUE
rb_ary_to_a(VALUE ary)
{
if (rb_obj_class(ary) != rb_cArray) {
VALUE dup = rb_ary_new2(RARRAY_LEN(ary));
rb_ary_replace(dup, ary);
return dup;
}
return ary;
}
当 self 是 Array 的实例时,返回 self。
否则,返回一个包含 self 元素的新数组
class MyArray < Array; end my_a = MyArray.new(['foo', 'bar', 'two']) a = my_a.to_a a # => ["foo", "bar", "two"] a.class # => Array # Not MyArray.
相关:请参阅 用于转换的方法。
来源
static VALUE
rb_ary_to_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;
}
返回由 self 形成的新哈希。
如果没有给出块,则 self 的每个元素必须是一个包含 2 个元素的子数组;将每个子数组形成新哈希中的键值对
a = [['foo', 'zero'], ['bar', 'one'], ['baz', 'two']] a.to_h # => {"foo"=>"zero", "bar"=>"one", "baz"=>"two"} [].to_h # => {}
如果给出了块,则该块必须返回一个包含 2 个元素的数组;使用 self 的每个元素调用该块;将每个返回的数组形成返回的哈希中的键值对
a = ['foo', :bar, 1, [2, 3], {baz: 4}] a.to_h {|element| [element, element.class] } # => {"foo"=>String, :bar=>Symbol, 1=>Integer, [2, 3]=>Array, {:baz=>4}=>Hash}
相关:请参阅 用于转换的方法。
返回通过调用每个数组元素的 inspect 方法形成的新字符串。
a = [:foo, 'bar', 2] a.inspect # => "[:foo, \"bar\", 2]"
相关:请参阅 用于转换的方法。
来源
static VALUE
rb_ary_transpose(VALUE ary)
{
long elen = -1, alen, i, j;
VALUE tmp, result = 0;
alen = RARRAY_LEN(ary);
if (alen == 0) return rb_ary_dup(ary);
for (i=0; i<alen; i++) {
tmp = to_ary(rb_ary_elt(ary, i));
if (elen < 0) { /* first element */
elen = RARRAY_LEN(tmp);
result = rb_ary_new2(elen);
for (j=0; j<elen; j++) {
rb_ary_store(result, j, rb_ary_new2(alen));
}
}
else if (elen != RARRAY_LEN(tmp)) {
rb_raise(rb_eIndexError, "element size differs (%ld should be %ld)",
RARRAY_LEN(tmp), elen);
}
for (j=0; j<elen; j++) {
rb_ary_store(rb_ary_elt(result, j), i, rb_ary_elt(tmp, j));
}
}
return result;
}
返回一个新数组,该数组是作为转置矩阵的 self
a = [[:a0, :a1], [:b0, :b1], [:c0, :c1]] a.transpose # => [[:a0, :b0, :c0], [:a1, :b1, :c1]]
self 的元素必须大小相同。
相关:请参阅 用于转换的方法。
来源
static VALUE
rb_ary_union_multi(int argc, VALUE *argv, VALUE ary)
{
int i;
long sum;
VALUE hash;
sum = RARRAY_LEN(ary);
for (i = 0; i < argc; i++) {
argv[i] = to_ary(argv[i]);
sum += RARRAY_LEN(argv[i]);
}
if (sum <= SMALL_ARRAY_LEN) {
VALUE ary_union = rb_ary_new();
rb_ary_union(ary_union, ary);
for (i = 0; i < argc; i++) rb_ary_union(ary_union, argv[i]);
return ary_union;
}
hash = ary_make_hash(ary);
for (i = 0; i < argc; i++) rb_ary_union_hash(hash, argv[i]);
return rb_hash_values(hash);
}
返回一个新数组,它是 self 和所有给定的数组 other_arrays 的元素的并集;使用 eql? 比较项目
[0, 1, 2, 3].union([4, 5], [6, 7]) # => [0, 1, 2, 3, 4, 5, 6, 7]
删除重复项(保留找到的第一个)
[0, 1, 1].union([2, 1], [3, 1]) # => [0, 1, 2, 3]
保留顺序(保留找到的第一个的位置)
[3, 2, 1, 0].union([5, 3], [4, 2]) # => [3, 2, 1, 0, 5, 4]
如果没有给出参数,则返回 self 的副本。
相关:请参阅 合并的方法。
来源
static VALUE
rb_ary_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 中不重复的元素的新数组,始终保留第一次出现的元素。
如果没有给出块,则使用方法 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_bang(VALUE ary)
{
VALUE hash;
long hash_size;
rb_ary_modify_check(ary);
if (RARRAY_LEN(ary) <= 1)
return Qnil;
if (rb_block_given_p())
hash = ary_make_hash_by(ary);
else
hash = ary_make_hash(ary);
hash_size = RHASH_SIZE(hash);
if (RARRAY_LEN(ary) == hash_size) {
return Qnil;
}
rb_ary_modify_check(ary);
ARY_SET_LEN(ary, 0);
if (ARY_SHARED_P(ary)) {
rb_ary_unshare(ary);
FL_SET_EMBED(ary);
}
ary_resize_capa(ary, hash_size);
rb_hash_foreach(hash, push_value, ary);
return ary;
}
从 self 中移除重复元素,始终保留第一次出现的元素;如果移除了任何元素,则返回 self,否则返回 nil。
如果没有给出块,则使用方法 eql? 比较元素来识别并删除元素
a = [0, 0, 1, 1, 2, 2] a.uniq! # => [0, 1, 2] a.uniq! # => nil
如果给出了块,则使用每个元素调用该块;使用方法 eql? 来比较块返回值,从而识别并省略“重复”元素;也就是说,如果一个元素的块返回值与之前元素的块返回值相同,则该元素为重复元素
a = ['a', 'aa', 'aaa', 'b', 'bb', 'bbb'] a.uniq! {|element| element.size } # => ["a", "aa", "aaa"] a.uniq! {|element| element.size } # => nil
相关:请参阅 删除方法。
来源
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;
}
将给定的 objects 前置到 self
a = [:foo, 'bar', 2] a.unshift(:bam, :bat) # => [:bam, :bat, :foo, "bar", 2]
相关:Array#shift;另请参阅用于赋值的方法。
来源
static VALUE
rb_ary_values_at(int argc, VALUE *argv, VALUE ary)
{
long i, olen = RARRAY_LEN(ary);
VALUE result = rb_ary_new_capa(argc);
for (i = 0; i < argc; ++i) {
append_values_at_single(result, ary, olen, argv[i]);
}
RB_GC_GUARD(ary);
return result;
}
在新数组中返回 self 中的元素;不修改 self。
返回的数组中包含的对象是 self 中由给定的 specifiers 选择的元素,每个 specifiers 必须是一个数值索引或一个 Range。
简而言之
a = ['a', 'b', 'c', 'd'] # Index specifiers. a.values_at(2, 0, 2, 0) # => ["c", "a", "c", "a"] # May repeat. a.values_at(-4, -3, -2, -1) # => ["a", "b", "c", "d"] # Counts backwards if negative. a.values_at(-50, 50) # => [nil, nil] # Outside of self. # Range specifiers. a.values_at(1..3) # => ["b", "c", "d"] # From range.begin to range.end. a.values_at(1...3) # => ["b", "c"] # End excluded. a.values_at(3..1) # => [] # No such elements. a.values_at(-3..3) # => ["b", "c", "d"] # Negative range.begin counts backwards. a.values_at(-50..3) # Raises RangeError. a.values_at(1..-2) # => ["b", "c"] # Negative range.end counts backwards. a.values_at(1..-50) # => [] # No such elements. # Mixture of specifiers. a.values_at(2..3, 3, 0..1, 0) # => ["c", "d", "d", "a", "b", "a"]
如果没有给出 specifiers,则返回一个新的空数组
a = ['a', 'b', 'c', 'd'] a.values_at # => []
对于每个数值说明符 index,包括一个元素
-
对于每个在范围内的非负数值说明符
index(小于self.size),包括偏移量为index的元素a.values_at(0, 2) # => ["a", "c"] a.values_at(0.1, 2.9) # => ["a", "c"]
-
对于每个在范围内的负数值
index(大于或等于- self.size),从self的末尾倒数a.values_at(-1, -4) # => ["d", "a"]
给定的索引可以是任何顺序,并且可以重复
a.values_at(2, 0, 1, 0, 2) # => ["c", "a", "b", "a", "c"]
对于每个超出范围的 index,包括 nil
a.values_at(4, -5) # => [nil, nil]
对于每个 Range 说明符 range,根据 range.begin 和 range.end 包括元素
-
如果
range.begin和range.end都是非负数且在范围内(小于self.size),则包括从索引range.begin到range.end - 1(如果range.exclude_end?),或到range.end(否则)的元素a.values_at(1..2) # => ["b", "c"] a.values_at(1...2) # => ["b"]
-
如果
range.begin为负数且在范围内(大于或等于- self.size),则从self的末尾倒数a.values_at(-2..3) # => ["c", "d"]
-
如果
range.begin为负数且超出范围,则引发异常a.values_at(-5..3) # Raises RangeError.
-
如果
range.end为正数且超出范围,则使用nil元素扩展返回的数组a.values_at(1..5) # => ["b", "c", "d", nil, nil]
-
如果
range.end为负数且在范围内,则从self的末尾倒数a.values_at(1..-2) # => ["b", "c"]
-
如果
range.end为负数且超出范围,则返回一个空数组a.values_at(1..-5) # => []
给定的范围可以是任何顺序,并且可以重复
a.values_at(2..3, 0..1, 2..3) # => ["c", "d", "a", "b", "c", "d"]
给定的说明符可以是索引和范围的任何混合
a.values_at(3, 1..2, 0, 2..3) # => ["d", "b", "c", "a", "c", "d"]
相关:请参阅 获取的方法。
来源
static VALUE
rb_ary_zip(int argc, VALUE *argv, VALUE ary)
{
int i, j;
long len = RARRAY_LEN(ary);
VALUE result = Qnil;
for (i=0; i<argc; i++) {
argv[i] = take_items(argv[i], len);
}
if (rb_block_given_p()) {
int arity = rb_block_arity();
if (arity > 1) {
VALUE work, *tmp;
tmp = ALLOCV_N(VALUE, work, argc+1);
for (i=0; i<RARRAY_LEN(ary); i++) {
tmp[0] = RARRAY_AREF(ary, i);
for (j=0; j<argc; j++) {
tmp[j+1] = rb_ary_elt(argv[j], i);
}
rb_yield_values2(argc+1, tmp);
}
if (work) ALLOCV_END(work);
}
else {
for (i=0; i<RARRAY_LEN(ary); i++) {
VALUE tmp = rb_ary_new2(argc+1);
rb_ary_push(tmp, RARRAY_AREF(ary, i));
for (j=0; j<argc; j++) {
rb_ary_push(tmp, rb_ary_elt(argv[j], i));
}
rb_yield(tmp);
}
}
}
else {
result = rb_ary_new_capa(len);
for (i=0; i<len; i++) {
VALUE tmp = rb_ary_new_capa(argc+1);
rb_ary_push(tmp, RARRAY_AREF(ary, i));
for (j=0; j<argc; j++) {
rb_ary_push(tmp, rb_ary_elt(argv[j], i));
}
rb_ary_push(result, tmp);
}
}
return result;
}
如果没有给出块,则将 self 与 other_arrays 的集合组合;返回一个子数组的新数组
[0, 1].zip(['zero', 'one'], [:zero, :one]) # => [[0, "zero", :zero], [1, "one", :one]]
返回的
-
外部数组的大小为
self.size。 -
每个子数组的大小为
other_arrays.size + 1。 -
第 n 个子数组包含(按顺序)
-
self的第 n 个元素。 -
每个其他数组的第 n 个元素(如果可用)。
-
示例
a = [0, 1] zipped = a.zip(['zero', 'one'], [:zero, :one]) # => [[0, "zero", :zero], [1, "one", :one]] zipped.size # => 2 # Same size as a. zipped.first.size # => 3 # Size of other arrays plus 1.
当其他数组的大小都与 self 相同时,返回的子数组是一个重新排列,其中包含所有数组(包括 self)的精确元素,没有省略或添加
a = [:a0, :a1, :a2, :a3] b = [:b0, :b1, :b2, :b3] c = [:c0, :c1, :c2, :c3] d = a.zip(b, c) pp d # => [[:a0, :b0, :c0], [:a1, :b1, :c1], [:a2, :b2, :c2], [:a3, :b3, :c3]]
当其他数组之一小于 self 时,用 nil 元素填充相应的子数组
a = [:a0, :a1, :a2, :a3] b = [:b0, :b1, :b2] c = [:c0, :c1] d = a.zip(b, c) pp d # => [[:a0, :b0, :c0], [:a1, :b1, :c1], [:a2, :b2, nil], [:a3, nil, nil]]
当其他数组之一大于 self 时,忽略其尾随元素
a = [:a0, :a1, :a2, :a3] b = [:b0, :b1, :b2, :b3, :b4] c = [:c0, :c1, :c2, :c3, :c4, :c5] d = a.zip(b, c) pp d # => [[:a0, :b0, :c0], [:a1, :b1, :c1], [:a2, :b2, :c2], [:a3, :b3, :c3]]
如果给出了块,则使用每个其他数组调用该块;返回 nil
d = [] a = [:a0, :a1, :a2, :a3] b = [:b0, :b1, :b2, :b3] c = [:c0, :c1, :c2, :c3] a.zip(b, c) {|sub_array| d.push(sub_array.reverse) } # => nil pp d # => [[:c0, :b0, :a0], [:c1, :b1, :a1], [:c2, :b2, :a2], [:c3, :b3, :a3]]
对于 other_arrays 中实际上不是数组的 对象,如果已定义,则将 “其他数组” 形式化为 object.to_ary,否则形式化为 object.each.to_a。
相关:请参阅 用于转换的方法。