第 13 章 數(shù)組類(lèi)
13.1 復(fù)習(xí)數(shù)組
數(shù)組是帶索引的對(duì)象的集合。
# 使用 [] 創(chuàng)建數(shù)組
>> names = ["Mike", "Tom", "Jim", "Ken"]
=> ["Mike", "Tom", "Jim", "Ken"]
# 可以從數(shù)組中獲取某個(gè)索引的元素(對(duì)象)
>> names[2]
=> "Jim"
# 可以將任意的值(對(duì)象)保存到數(shù)組的某個(gè)索引的元素中
>> names[0] = "Alex"
=> "Alex"
>> names
=> ["Alex", "Tom", "Jim", "Ken"]
# 使用迭代器可以逐個(gè)取出數(shù)組中的元素
=> ["Alex", "Tom", "Jim", "Ken"]
>> names.each{|name| puts name}
Alex
Tom
Jim
Ken
13.2 數(shù)組的創(chuàng)建方法
使用 []
創(chuàng)建數(shù)組
>> 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
創(chuàng)建類(lèi)的實(shí)例時(shí)使用的 new
方法怒见,創(chuàng)建數(shù)組時(shí)也同樣可以使用篷朵。
# 若 new 方法沒(méi)有參數(shù)荚板,則會(huì)創(chuàng)建元素個(gè)數(shù)為 0 的數(shù)組
>> a = Array.new
=> []
# 若 new 方法只有 1 個(gè)參數(shù)欠啤,則會(huì)創(chuàng)建元素個(gè)數(shù)為該參數(shù)個(gè)數(shù)哗咆,且各元素初始值都為 nil 的數(shù)組。
>> Array.new(5)
=> [nil, nil, nil, nil, nil]
# 若 new 方法有兩個(gè)參數(shù)猾担, 則第 1 個(gè)參數(shù)代表元素的個(gè)數(shù)袭灯,第 2 個(gè)參數(shù)代表元素值的初始值。
>> Array.new(5, 0)
=> [0, 0, 0, 0, 0]
13.2.2 使用 %w
與 %i
使用 %w
創(chuàng)建不包含空白的字符串?dāng)?shù)組
>> lang = %w(Ruby Perl Python Scheme Pike REBOL)
=> ["Ruby", "Perl", "Python", "Scheme", "Pike", "REBOL"]
使用 %i
創(chuàng)建符號(hào)數(shù)組
>> lang = %i(Ruby Perl Python Scheme Pike REBOL)
=> [:Ruby, :Perl, :Python, :Scheme, :Pike, :REBOL]
13.2.3 使用 to_a
方法
很多類(lèi)都定義了 to_a
方法绑嘹,該方法能把該類(lèi)的對(duì)象轉(zhuǎn)換為數(shù)組稽荧。
# 對(duì)散列對(duì)象使用 to_a 方法,結(jié)果就會(huì)得到相應(yīng)的數(shù)組的數(shù)組圾叼。
>> color_table = {black: "#000000", white: "#FFFFFF"}
=> {:black=>"#000000", :white=>"#FFFFFF"}
>> color_table.to_a
=> [[:black, "#000000"], [:white, "#FFFFFF"]]
13.2.4 使用字符串的 split
方法
對(duì)用逗號(hào)或者空白間隔的字符串使用 split
方法蛤克,也可以創(chuàng)建數(shù)組捺癞。
>> 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 獲取元素
通過(guò) []
指定索引夷蚊,獲取元素。
>> alpha = ["a", "b", "c", "d", "e"]
=> ["a", "b", "c", "d", "e"]
# 數(shù)組的索引從 0 開(kāi)始
>> alpha[1]
=> "b"
# 索引值為負(fù)數(shù)時(shí)髓介,從數(shù)組的末尾開(kāi)始獲取元素惕鼓。
>> alpha[-1]
=> "e"
>> alpha[-2]
=> "d"
# 指定索引范圍,創(chuàng)建新數(shù)組并返回唐础。
>> alpha[1..3] # 包括索引為 3 的元素
=> ["b", "c", "d"]
>> alpha[1...3] # 不包括索引為 3 的元素
=> ["b", "c"]
>> alpha[1..7] # 索引值比數(shù)組長(zhǎng)度大時(shí)箱歧,返回?cái)?shù)組最后一個(gè)元素。
=> ["b", "c", "d", "e"]
# 從某個(gè)元素開(kāi)始一膨,獲取多個(gè)元素呀邢。
>> alpha[2, 2]
=> ["c", "d"]
>> alpha[2, 3]
=> ["c", "d", "e"]
通過(guò)數(shù)組方法指定索引,獲取元素豹绪。
>> 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 元素賦值
對(duì)一個(gè)元素賦值
>> 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"]
對(duì)多個(gè)元素賦值
>> 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 插入元素
插入元素其實(shí)也可以被認(rèn)為是對(duì) 0 個(gè)元素進(jìn)行賦值价淌。因此,指定 [0, n]
后瞒津,就會(huì)在索引值為 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 通過(guò)多個(gè)索引創(chuàng)建數(shù)組
使用 values_at
方法,可以利用多個(gè)索引來(lái)分散獲取多個(gè)元素巷蚪,并用它們創(chuàng)建新數(shù)組病毡。
>> 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 作為集合的數(shù)組
>> ary1 = ["a", "b", "c"]
=> ["a", "b", "c"]
>> ary2 = ["b", "c", "d"]
=> ["b", "c", "d"]
# 交集運(yùn)算
>> ary1 & ary2
=> ["b", "c"]
# 并集運(yùn)算
>> ary1 | ary2
=> ["a", "b", "c", "d"]
# 差集運(yùn)算
>> ary1 - ary2
=> ["a"]
|
與 +
的不同點(diǎn)
>> 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 作為列的數(shù)組
隊(duì)列:按元素被追加時(shí)的順序來(lái)獲取元素的數(shù)據(jù)結(jié)構(gòu),也就是“先進(jìn)先出”屁柏。
棧:按與元素被追加時(shí)的順序相反的順序來(lái)獲取元素的數(shù)據(jù)結(jié)構(gòu)啦膜,也就是“后進(jìn)先出”有送。
操作數(shù)組開(kāi)頭與末尾的元素的方法
元素操作 | 對(duì)數(shù)組開(kāi)頭的元素操作 | 對(duì)數(shù)組末尾的元素操作 |
---|---|---|
追加元素 | unshift | push |
刪除元素 | shift | pop |
引用元素 | first | last |
>> alpha = ["b", "c", "d", "e"]
=> ["b", "c", "d", "e"]
# 在數(shù)組的開(kāi)頭插入元素
>> alpha.unshift("A")
=> ["A", "b", "c", "d", "e"]
>> alpha
=> ["A", "b", "c", "d", "e"]
# 刪除數(shù)組開(kāi)頭的元素并將其作為返回值
>> alpha.shift
=> "A"
>> alpha
=> ["b", "c", "d", "e"]
>> alpha = ["a", "b", "c", "d"]
=> ["a", "b", "c", "d"]
# 在數(shù)組的末尾插入元素
>> alpha.push("E")
=> ["a", "b", "c", "d", "E"]
>> alpha
=> ["a", "b", "c", "d", "E"]
# 刪除數(shù)組末尾的元素并將其作為返回值
>> alpha.pop
=> "E"
>> alpha
=> ["a", "b", "c", "d"]
>> a = [1, 2, 3, 4, 5]
=> [1, 2, 3, 4, 5]
# 獲取數(shù)組開(kāi)頭的元素
>> a.first
=> 1
# 獲取數(shù)組末尾的元素
>> a.last
=> 5
隊(duì)列的實(shí)現(xiàn):先進(jìn)先出
>> 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
=> []
棧的實(shí)現(xiàn):后進(jìn)先出
>> 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 主要的數(shù)組的方法
13.6.1 為數(shù)組添加元素
a.unshift(item)
將 item 元素添加到數(shù)組的開(kāi)頭
>> 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 << item
與a.push(item)
是等價(jià)的方法
在數(shù)組的末尾插入元素
>> 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 是具有破壞性的方法,原有數(shù)組會(huì)被改變功戚。
>> a.concat([8, 9])
=> [1, 2, 3, 4, 5, 8, 9]
>> a
=> [1, 2, 3, 4, 5, 8, 9]
# 而 + 則會(huì)返回一個(gè)新創(chuàng)建的數(shù)組娶眷,原有數(shù)組不會(huì)被改變。
>> 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)
把數(shù)組 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]
專(zhuān)欄:具有破壞性的方法
會(huì)改變方法(也成為消息)接收者對(duì)象值的方法稱(chēng)為具有破壞性的方法啸臀。使用具有破壞性的方法時(shí)要特別小心届宠,因?yàn)楫?dāng)有變量也引用了接收者對(duì)象時(shí),如果接收者對(duì)象發(fā)生了改變乘粒,變量值也會(huì)隨之發(fā)生變化豌注。
>> 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 的方法中,有像 sort
和 sort!
這樣灯萍,在相同方法名后加上 !
的方法轧铁。為了區(qū)分方法是否具有破壞性,在具有破壞性的方法末尾添加 !
旦棉。
# 不具有破壞性的方法
>> 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 從數(shù)組中刪除元素
- 從數(shù)組中刪除所有
nil
元素
a.compact
a.compact!
>> a = [1, nil, 3, nil, nil]
=> [1, nil, 3, nil, nil]
>> a.compact!
=> [1, 3]
>> a
=> [1, 3]
- 從數(shù)組中刪除指定索引的元素
a.delete_at(n)
>> a = [1, 2, 3, 4, 5]
=> [1, 2, 3, 4, 5]
>> a.delete_at(2)
=> 3
- 刪除滿(mǎn)足條件的元素
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]
- 刪除數(shù)組中重復(fù)的元素
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]
- 刪除數(shù)組開(kāi)頭的元素
a.shift
>> a = [1, 2, 3, 4, 5]
=> [1, 2, 3, 4, 5]
>> a.shift
=> 1
>> a
=> [2, 3, 4, 5]
- 刪除數(shù)組末尾的元素
a.pop
>> a = [1, 2, 3, 4, 5]
=> [1, 2, 3, 4, 5]
>> a.pop
=> 5
>> a
=> [1, 2, 3, 4]
13.6.3 替換數(shù)組元素
- 數(shù)組映射
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]
- 數(shù)組平鋪
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]
- 展開(kāi)嵌套數(shù)組
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]
- 反轉(zhuǎn)數(shù)組的順序
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]
- 對(duì)數(shù)組進(jìn)行排序
a.sort
a.sort!
a.sort{ |i, j| ... }
a.sort!{ |i, j| ... }
沒(méi)有塊時(shí)齿风,使用 <=>
運(yùn)算符比較
>> a = [2, 4, 3, 5, 1]
=> [2, 4, 3, 5, 1]
>> a.sort!
=> [1, 2, 3, 4, 5]
>> a
=> [1, 2, 3, 4, 5]
- 根據(jù)數(shù)組映射對(duì)數(shù)組的所有元素進(jìn)行排序
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 數(shù)組與迭代器
典型的迭代器 each
>> [1, 4, 5, 3, 2].each{|item| puts item}
1
4
5
3
2
=> [1, 4, 5, 3, 2]
接收者不是數(shù)組時(shí),為了讓迭代器的執(zhí)行結(jié)果作為某個(gè)對(duì)象返回绑洛,也會(huì)用到數(shù)組救斑。
>> a = 1..5
=> 1..5
>> a.collect{|i| i += 2}
=> [3, 4, 5, 6, 7]
>> a
=> 1..5
13.8 處理數(shù)組中的元素
13.8.1 使用循環(huán)與索引
list = ["a", "b", "c", "d"]
for i in 0..3
print "第 ", i+1, " 個(gè)元素是 ", list[i], "。\n"
end
結(jié)果:
第 1 個(gè)元素是 a真屯。
第 2 個(gè)元素是 b脸候。
第 3 個(gè)元素是 c。
第 4 個(gè)元素是 d
list = [1, 3, 5, 7, 9]
sum = 0
for i in 0..4
sum += list[i]
end
print "合計(jì):", sum, "\n"
結(jié)果:
合計(jì):25
13.8.2 使用 each
方法逐個(gè)獲取元素
list = [1, 3, 5, 7, 9]
sum = 0
list.each do |elem|
sum += elem
end
print "合計(jì):", sum, "\n"
結(jié)果:同上
list = ["a", "b", "c", "d"]
list.each_with_index do |elem, i|
print "第 ", i+1, " 個(gè)元素是 ", elem, "绑蔫。\n"
end
結(jié)果:同上
13.8.3 使用具有破壞性的方法實(shí)現(xiàn)循環(huán)
a = [10, 20, 30, 40, 50]
while item = a.pop
puts item
end
puts "After While: a = #{a}"
結(jié)果:
50
40
30
20
10
After While: a = []
13.9 數(shù)組的元素
13.9.1 使用簡(jiǎn)單的矩陣
>> 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 初始化時(shí)的注意事項(xiàng)
各個(gè)元素引用同一個(gè)對(duì)象
>> 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
方法的塊和元素個(gè)數(shù)运沦,程序調(diào)用與元素個(gè)數(shù)一樣次數(shù)的塊,然后再將塊的返回值賦值給元素配深。每次調(diào)用塊都會(huì)生成新的對(duì)象携添,這樣一來(lái),各個(gè)元素引用同一個(gè)對(duì)象的問(wèn)題就不會(huì)發(fā)生了篓叶。
a = Array.new(3) do
[0, 0, 0]
end
p a
a[0][1] = 2
p a
結(jié)果:
[[0, 0, 0], [0, 0, 0], [0, 0, 0]]
[[0, 2, 0], [0, 0, 0], [0, 0, 0]]
另一個(gè)例子
>> a = Array.new(5){|i| i + 1}
=> [1, 2, 3, 4, 5]
13.10 同時(shí)訪(fǎng)問(wèn)多個(gè)數(shù)組
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
結(jié)果
[111, 222, 333, 444, 555]