第 13 章 数组类

第 13 章 数组类

13.1 复习数组

数组是带索引的对象的集合。

# 使用 [] 创建数组
>> names = ["Mike", "Tom", "Jim", "Ken"]
=> ["Mike", "Tom", "Jim", "Ken"]

# 可以从数组中获取某个索引的元素(对象)
>> names[2]
=> "Jim"

# 可以将任意的值(对象)保存到数组的某个索引的元素中
>> names[0] = "Alex"
=> "Alex"
>> names
=> ["Alex", "Tom", "Jim", "Ken"]

# 使用迭代器可以逐个取出数组中的元素
=> ["Alex", "Tom", "Jim", "Ken"]
>> names.each{|name| puts name}
Alex
Tom
Jim
Ken

13.2 数组的创建方法

使用 [] 创建数组

>> nums = [1, 2, 3, 4, 5]
=> [1, 2, 3, 4, 5]
>> strs = ["a", "b", "c", "d"]
=> ["a", "b", "c", "d"]

13.2.1 使用 Array.new

创建类的实例时使用的 new 方法,创建数组时也同样可以使用。


# 若 new 方法没有参数,则会创建元素个数为 0 的数组
>> a = Array.new
=> []

# 若 new 方法只有 1 个参数,则会创建元素个数为该参数个数,且各元素初始值都为 nil 的数组。
>> Array.new(5)
=> [nil, nil, nil, nil, nil]

# 若 new 方法有两个参数, 则第 1 个参数代表元素的个数,第 2 个参数代表元素值的初始值。
>> Array.new(5, 0)
=> [0, 0, 0, 0, 0]

13.2.2 使用 %w%i

使用 %w 创建不包含空白的字符串数组

>> lang = %w(Ruby Perl Python Scheme Pike REBOL)
=> ["Ruby", "Perl", "Python", "Scheme", "Pike", "REBOL"]

使用 %i 创建符号数组

>> lang = %i(Ruby Perl Python Scheme Pike REBOL)
=> [:Ruby, :Perl, :Python, :Scheme, :Pike, :REBOL]

13.2.3 使用 to_a 方法

很多类都定义了 to_a 方法,该方法能把该类的对象转换为数组。

# 对散列对象使用 to_a 方法,结果就会得到相应的数组的数组。
>> color_table = {black: "#000000", white: "#FFFFFF"}
=> {:black=>"#000000", :white=>"#FFFFFF"}
>> color_table.to_a
=> [[:black, "#000000"], [:white, "#FFFFFF"]]

13.2.4 使用字符串的 split 方法

对用逗号或者空白间隔的字符串使用 split 方法,也可以创建数组。

>> column = "2013/05/30 22:33 foo.html proxy.example.jp".split()
=> ["2013/05/30", "22:33", "foo.html", "proxy.example.jp"]

13.3 索引的使用方法

13.3.1 获取元素

通过 [] 指定索引,获取元素。

>> alpha = ["a", "b", "c", "d", "e"]
=> ["a", "b", "c", "d", "e"]

# 数组的索引从 0 开始
>> alpha[1]
=> "b"

# 索引值为负数时,从数组的末尾开始获取元素。
>> alpha[-1]
=> "e"
>> alpha[-2]
=> "d"

# 指定索引范围,创建新数组并返回。
>> alpha[1..3] # 包括索引为 3 的元素
=> ["b", "c", "d"]
>> alpha[1...3] # 不包括索引为 3 的元素
=> ["b", "c"]
>> alpha[1..7] # 索引值比数组长度大时,返回数组最后一个元素。
=> ["b", "c", "d", "e"]

# 从某个元素开始,获取多个元素。
>> alpha[2, 2]
=> ["c", "d"]
>> alpha[2, 3]
=> ["c", "d", "e"]

通过数组方法指定索引,获取元素。

>> alpha.at(1)
=> "b"
>> alpha.at(-1)
=> "e"
>> alpha.at(-2)
=> "d"
>> alpha.slice(1)
=> "b"
>> alpha.slice(-1)
=> "e"
>> alpha.slice(-2)
=> "d"
>> alpha.slice(1..3)
=> ["b", "c", "d"]
>> alpha.slice(1...3)
=> ["b", "c"]
>> alpha.slice(1..7)
=> ["b", "c", "d", "e"]
>> alpha.slice(2, 2)
=> ["c", "d"]
>> alpha.slice(2, 3)
=> ["c", "d", "e"]

13.3.2 元素赋值

对一个元素赋值

>> alpha = ["a", "b", "c", "d", "e", "f"]
=> ["a", "b", "c", "d", "e", "f"]
>> alpha[1] = "B"
=> "B"
>> alpha[4] = "E"
=> "E"
>> alpha
=> ["a", "B", "c", "d", "E", "f"]

对多个元素赋值

>> alpha = ["a", "b", "c", "d", "e", "f"]
=> ["a", "b", "c", "d", "e", "f"]
>> alpha[2, 3] = ["C", "D", "E"]
=> ["C", "D", "E"]
>> alpha
=> ["a", "b", "C", "D", "E", "f"]

13.3.3 插入元素

插入元素其实也可以被认为是对 0 个元素进行赋值。因此,指定 [0, n] 后,就会在索引值为 n 的元素前插入元素。

>> alpha = ["a", "b", "c", "d", "e", "f"]
=> ["a", "b", "c", "d", "e", "f"]
>> alpha[2, 0] = ["X", "Y"]
=> ["X", "Y"]
>> alpha
=> ["a", "b", "X", "Y", "c", "d", "e", "f"]

13.3.4 通过多个索引创建数组

使用 values_at 方法,可以利用多个索引来分散获取多个元素,并用它们创建新数组。

>> alpha = %w(a b c d e f)
=> ["a", "b", "c", "d", "e", "f"]
>> alpha.values_at(1, 3, 5)
=> ["b", "d", "f"]

13.4 作为集合的数组

>> ary1 = ["a", "b", "c"]
=> ["a", "b", "c"]
>> ary2 = ["b", "c", "d"]
=> ["b", "c", "d"]

# 交集运算
>> ary1 & ary2
=> ["b", "c"]

# 并集运算
>> ary1 | ary2
=> ["a", "b", "c", "d"]

# 差集运算
>> ary1 - ary2
=> ["a"]

|+ 的不同点

>> num = [1, 2, 3]
=> [1, 2, 3]
>> even = [2, 4, 6]
=> [2, 4, 6]
>> num + even
=> [1, 2, 3, 2, 4, 6]
>> num | even
=> [1, 2, 3, 4, 6]

13.5 作为列的数组

队列:按元素被追加时的顺序来获取元素的数据结构,也就是“先进先出”。

栈:按与元素被追加时的顺序相反的顺序来获取元素的数据结构,也就是“后进先出”。

操作数组开头与末尾的元素的方法

元素操作 对数组开头的元素操作 对数组末尾的元素操作
追加元素 unshift push
删除元素 shift pop
引用元素 first last
>> alpha = ["b", "c", "d", "e"]
=> ["b", "c", "d", "e"]

# 在数组的开头插入元素
>> alpha.unshift("A")
=> ["A", "b", "c", "d", "e"]
>> alpha
=> ["A", "b", "c", "d", "e"]

# 删除数组开头的元素并将其作为返回值
>> alpha.shift
=> "A"
>> alpha
=> ["b", "c", "d", "e"]
>> alpha = ["a", "b", "c", "d"]
=> ["a", "b", "c", "d"]

# 在数组的末尾插入元素
>> alpha.push("E")
=> ["a", "b", "c", "d", "E"]
>> alpha
=> ["a", "b", "c", "d", "E"]

# 删除数组末尾的元素并将其作为返回值
>> alpha.pop
=> "E"
>> alpha
=> ["a", "b", "c", "d"]
>> a = [1, 2, 3, 4, 5]
=> [1, 2, 3, 4, 5]

# 获取数组开头的元素
>> a.first
=> 1

# 获取数组末尾的元素
>> a.last
=> 5

队列的实现:先进先出

>> queue = []
=> []
>> queue.push("a")
=> ["a"]
>> queue.push("b")
=> ["a", "b"]
>> queue.push("c")
=> ["a", "b", "c"]
>> queue.shift
=> "a"
>> queue
=> ["b", "c"]
>> queue.shift
=> "b"
>> queue
=> ["c"]
>> queue.shift
=> "c"
>> queue
=> []

栈的实现:后进先出

>> stack = []
=> []
>> stack.push("a")
=> ["a"]
>> stack.push("b")
=> ["a", "b"]
>> stack.push("c")
=> ["a", "b", "c"]
>> stack.pop
=> "c"
>> stack
=> ["a", "b"]
>> stack.pop
=> "b"
>> stack
=> ["a"]
>> stack.pop
=> "a"
>> stack
=> []

13.6 主要的数组的方法

13.6.1 为数组添加元素

  • a.unshift(item)

将 item 元素添加到数组的开头

>> a = [1, 2, 3, 4, 5]
=> [1, 2, 3, 4, 5]
>> a.unshift(0)
=> [0, 1, 2, 3, 4, 5]
>> a
=> [0, 1, 2, 3, 4, 5]
  • a << itema.push(item) 是等价的方法

在数组的末尾插入元素

>> a = [1, 2, 3, 4, 5]
=> [1, 2, 3, 4, 5]
>> a << 6
=> [1, 2, 3, 4, 5, 6]
>> a.push(7)
=> [1, 2, 3, 4, 5, 6, 7]
>> a = [1, 2, 3, 4, 5]
=> [1, 2, 3, 4, 5]

# concat 是具有破坏性的方法,原有数组会被改变。
>> a.concat([8, 9])
=> [1, 2, 3, 4, 5, 8, 9]
>> a
=> [1, 2, 3, 4, 5, 8, 9]

# 而 + 则会返回一个新创建的数组,原有数组不会被改变。
>> a = [1, 2, 3, 4, 5]
=> [1, 2, 3, 4, 5]
>> a + [8, 9]
=> [1, 2, 3, 4, 5, 8, 9]
>> a
=> [1, 2, 3, 4, 5]
  • a[n] = item a[n..m] = item(s) a[n, len] = item(s)

把数组 a 指定范围的元素替换为 item(s)

>> a = [1, 2, 3, 4, 5, 6, 7, 8]
=> [1, 2, 3, 4, 5, 6, 7, 8]
>> a[2..4] = 0
=> 0
>> a
=> [1, 2, 0, 6, 7, 8]
>> a[1, 3] = 9
=> 9
>> a
=> [1, 9, 7, 8]

专栏:具有破坏性的方法

会改变方法(也成为消息)接收者对象值的方法称为具有破坏性的方法。使用具有破坏性的方法时要特别小心,因为当有变量也引用了接收者对象时,如果接收者对象发生了改变,变量值也会随之发生变化。

>> a = [1, 2, 3, 4]
=> [1, 2, 3, 4]
>> b = a
=> [1, 2, 3, 4]
>> b.pop
=> 4
>> b
=> [1, 2, 3]
>> a
=> [1, 2, 3]

在 Ruby 的方法中,有像 sortsort! 这样,在相同方法名后加上 ! 的方法。为了区分方法是否具有破坏性,在具有破坏性的方法末尾添加 !

# 不具有破坏性的方法
>> a = [1, 3, 2, 5, 4]
=> [1, 3, 2, 5, 4]
>> a.sort
=> [1, 2, 3, 4, 5]
>> a
=> [1, 3, 2, 5, 4]

# 具有破坏性的方法
>> a = [1, 3, 2, 5, 4]
=> [1, 3, 2, 5, 4]
>> a.sort!
=> [1, 2, 3, 4, 5]
>> a
=> [1, 2, 3, 4, 5]

13.6.2 从数组中删除元素

  • 从数组中删除所有 nil 元素

a.compact
a.compact!

>> a = [1, nil, 3, nil, nil]
=> [1, nil, 3, nil, nil]
>> a.compact!
=> [1, 3]
>> a
=> [1, 3]
  • 从数组中删除指定索引的元素

a.delete_at(n)

>> a = [1, 2, 3, 4, 5]
=> [1, 2, 3, 4, 5]
>> a.delete_at(2)
=> 3
  • 删除满足条件的元素

a.delete_if{ |item| ... }

>> a = [1, 2, 3, 4, 5]
=> [1, 2, 3, 4, 5]
>> a.delete_if{|i| i > 3}
=> [1, 2, 3]
>> a
=> [1, 2, 3]

a.reject{ |item| ... }
a.reject!{ |item| ... }

>> a = [1, 2, 3, 4, 5]
=> [1, 2, 3, 4, 5]
>> a.reject!{|i| i > 3}
=> [1, 2, 3]
>> a
=> [1, 2, 3]
  • 删除指定范围的元素

a.slice!(n)

>> a = [1, 2, 3, 4, 5]
=> [1, 2, 3, 4, 5]
>> a.slice!(1)
=> 2
>> a
=> [1, 3, 4, 5]

a.slice!(n..m)

>> a = [1, 2, 3, 4, 5]
=> [1, 2, 3, 4, 5]
>> a.slice!(1..3)
=> [2, 3, 4]
>> a
=> [1, 5]

a.slice!(n, len)

>> a = [1, 2, 3, 4, 5]
=> [1, 2, 3, 4, 5]
>> a.slice!(1, 2)
=> [2, 3]
>> a
=> [1, 4, 5]
  • 删除数组中重复的元素

a.uniq
a.uniq!

>> a = [1, 2, 3, 4, 2, 1]
=> [1, 2, 3, 4, 2, 1]
>> a.uniq!
=> [1, 2, 3, 4]
>> a
=> [1, 2, 3, 4]
  • 删除数组开头的元素

a.shift

>> a = [1, 2, 3, 4, 5]
=> [1, 2, 3, 4, 5]
>> a.shift
=> 1
>> a
=> [2, 3, 4, 5]
  • 删除数组末尾的元素

a.pop

>> a = [1, 2, 3, 4, 5]
=> [1, 2, 3, 4, 5]
>> a.pop
=> 5
>> a
=> [1, 2, 3, 4]

13.6.3 替换数组元素

  • 数组映射

a.collect { |item| ... }
a.collect!{ |item| ... }

>> a = [1, 2, 3, 4, 5]
=> [1, 2, 3, 4, 5]
>> a.collect!{|item| item * 2}
=> [2, 4, 6, 8, 10]
>> a
=> [2, 4, 6, 8, 10]

a.map { |item| ... }
a.map! { |item| ... }

>> a = [1, 2, 3, 4, 5]
=> [1, 2, 3, 4, 5]
>> a.map!{|item| item * 2}
=> [2, 4, 6, 8, 10]
>> a
=> [2, 4, 6, 8, 10]
  • 数组平铺

a.fill(value)

>> [1, 2, 3, 4, 5].fill(0)
=> [0, 0, 0, 0, 0]

a.fill(value, begin)

>> [1, 2, 3, 4, 5].fill(0, 2)
=> [1, 2, 0, 0, 0]

a.fill(value, begin, len)

>> [1, 2, 3, 4, 5].fill(0, 2, 2)
=> [1, 2, 0, 0, 5]

a.fill(value, n..m)

>> [1, 2, 3, 4, 5].fill(0, 2..3)
=> [1, 2, 0, 0, 5]
  • 展开嵌套数组

a.flatten
a.flatten!

>> a = [1, [2, [3]], [4], 5]
=> [1, [2, [3]], [4], 5]
>> a.flatten!
=> [1, 2, 3, 4, 5]
>> a
=> [1, 2, 3, 4, 5]
  • 反转数组的顺序

a.reverse a.reverse!

>> a = [1, 2, 3, 4, 5]
=> [1, 2, 3, 4, 5]
>> a.reverse!
=> [5, 4, 3, 2, 1]
>> a
=> [5, 4, 3, 2, 1]
  • 对数组进行排序

a.sort
a.sort!
a.sort{ |i, j| ... }
a.sort!{ |i, j| ... }
没有块时,使用 <=> 运算符比较

>> a = [2, 4, 3, 5, 1]
=> [2, 4, 3, 5, 1]
>> a.sort!
=> [1, 2, 3, 4, 5]
>> a
=> [1, 2, 3, 4, 5]
  • 根据数组映射对数组的所有元素进行排序

a.sort_by{ |i| ... }

>> a = [2, 4, 3, 5, 1]
=> [2, 4, 3, 5, 1]
>> a.sort_by{|i| -i}
=> [5, 4, 3, 2, 1]
>> a
=> [2, 4, 3, 5, 1]

13.7 数组与迭代器

典型的迭代器 each

>> [1, 4, 5, 3, 2].each{|item| puts item}
1
4
5
3
2
=> [1, 4, 5, 3, 2]

接收者不是数组时,为了让迭代器的执行结果作为某个对象返回,也会用到数组。

>> a = 1..5
=> 1..5
>> a.collect{|i| i += 2}
=> [3, 4, 5, 6, 7]
>> a
=> 1..5

13.8 处理数组中的元素

13.8.1 使用循环与索引

list = ["a", "b", "c", "d"]
for i in 0..3
    print "第 ", i+1, " 个元素是 ", list[i], "。\n"
end

结果:

第 1 个元素是 a。
第 2 个元素是 b。
第 3 个元素是 c。
第 4 个元素是 d
list = [1, 3, 5, 7, 9]
sum = 0
for i in 0..4
    sum += list[i]
end
print "合计:", sum, "\n"

结果:

合计:25

13.8.2 使用 each 方法逐个获取元素

list = [1, 3, 5, 7, 9]
sum = 0
list.each do |elem|
    sum += elem
end
print "合计:", sum, "\n"

结果:同上

list = ["a", "b", "c", "d"]
list.each_with_index do |elem, i|
    print "第 ", i+1, " 个元素是 ", elem, "。\n"
end

结果:同上

13.8.3 使用具有破坏性的方法实现循环

a = [10, 20, 30, 40, 50]
while item = a.pop
    puts item
end
puts "After While: a = #{a}"

结果:

50
40
30
20
10
After While: a = []

13.9 数组的元素

13.9.1 使用简单的矩阵

>> a = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
=> [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
>> a[1][2]
=> 6

13.9.2 初始化时的注意事项

各个元素引用同一个对象

>> a = Array.new(3, [0, 0, 0])
=> [[0, 0, 0], [0, 0, 0], [0, 0, 0]]
>> a[0][1] = 2
=> 2
>> a
=> [[0, 2, 0], [0, 2, 0], [0, 2, 0]]

指定 new 方法的块和元素个数,程序调用与元素个数一样次数的块,然后再将块的返回值赋值给元素。每次调用块都会生成新的对象,这样一来,各个元素引用同一个对象的问题就不会发生了。

a = Array.new(3) do
    [0, 0, 0]    
end
p a

a[0][1] = 2
p a

结果:

[[0, 0, 0], [0, 0, 0], [0, 0, 0]]
[[0, 2, 0], [0, 0, 0], [0, 0, 0]]

另一个例子

>> a = Array.new(5){|i| i + 1}
=> [1, 2, 3, 4, 5]

13.10 同时访问多个数组

ary1 = [1, 2, 3, 4, 5]
ary2 = [10, 20, 30, 40, 50]
ary3 = [100, 200, 300, 400, 500]

result = []

ary1.zip(ary2, ary3) do |a, b, c|
    result << a + b + c
end

p result

结果

[111, 222, 333, 444, 555]

你可能感兴趣的:(第 13 章 数组类)