Ruby數組(2):數組方法詳細整理

數組方法整理

方法列表:php

  • all()、any()、none()和one():測試數組中的全部或部分元素是否知足給定條件。條件能夠是語句塊中決定,也能夠是參數決定
  • append():等價於push()
  • bsearch():二分法查找元素
  • bsearch_index():二分法查找元素並返回索引位置
  • count():計算數組中知足條件的元素個數,length()、size()和不帶參數的count()等價
  • collect()和collect!():等價於map
  • combination():對數組元素進行排列操做,see also:permutation()
  • compact()和compact!():移除數組中全部的nil元素
  • cycle():循環迭代整個數組屢次
  • delete():刪除數組中等於某值的元素,注意原處修改
  • delete_at():刪除數組中某索引位置處的元素,相似於slice!(),注意原處修改
  • delete_if():直接從數組中刪除知足語句塊中條件的元素,將剩下的元素做爲數組返回。注意:它是原處修改
  • dig():從嵌套數組中逐層取元素
  • drop():從前向後開始刪除n個元素,將剩下的元素做爲新數組返回,不是原處修改
  • drop_while():從前向後開始刪除元素,直到遇到第一個不知足語句塊中條件的元素
  • fetch():獲取給定索引處的元素,但可定義索引越界時的處理邏輯
  • fill():替換、修改給定範圍的元素
  • filter()和filter!():等價於select()、select!()
  • first():返回數組頭部的一個或多個元素
  • flatten()和flatten!():按層次將嵌套數組壓平
  • hash:計算數組的hash值,eql?方法比較對象時採用的是hash值比較
  • include?():判斷數組中是否存在某元素
  • index()和rindex():搜索數組中某元素的索引位置
  • initialize_copy():使用另外一數組中元素替換當前數組元素
  • keep_if():直接從數組中刪除不知足語句塊中條件的元素,將剩下的元素做爲數組返回。即保留知足條件的元素。注意:它是原處修改
  • last():返回數組尾部的一個或多個元素
  • length():返回數組元素個數,length()、size()和不帶參數的count()等價
  • map()和map!():迭代數組中每一個元素並對它們每個都執行語句塊中的邏輯
  • permutation():對數組元素做組合操做,see also:combination()
  • pop():從數組尾部移除1或多個元素並返回移除的元素
  • prepend():等價於unshift()
  • product():將多個數組的各個元素進行組合
  • push():向數組尾部追加1或多個元素並返回追加後的數組,等價於append()
  • reject()和reject!():根據語句塊中的規則篩選數組中不知足條件的元素
  • repeated_combination():看示例
  • repeated_permutation():看示例
  • replace():等價於initialize_copy()
  • reverse()和reverse!():反轉數組
  • reverse_each():反向迭代數組
  • rotate()和rotate!():轉動數組
  • select()和select!():根據語句塊中的規則篩選數組中知足條件的元素,相似於Perl中的grep()
  • simple():從數組中選取一個或n個隨機元素
  • shift():移除數組頭部的一個或多個元素,並返回移除的元素
  • shuffle()和shuffle!():打亂數組
  • size():返回數組元素個數,length()、size()和不帶參數的count()等價
  • sum():將數組各元素相加,不限於數值相加
  • sort()和sort!():對數組進行排序
  • sort_by():按規則對數組元素排序
  • take():從前向後開始返回n個元素
  • take_while():從前向後開始返回元素,直到遇到第一個不知足語句塊中條件的元素
  • transpose():對多維數組行列轉換,相似於zip()的特殊狀況
  • uniq()和uniq!():對數組去除重複元素
  • unshift():向數組頭部插入1個或多個給定元素並返回插入後的數組
  • zip():合併多數組的元素

map()和map!()

迭代數組中每一個元素,並對它們每個都執行塊中的邏輯,並返回新數組。java

map()不會修改原始數組對象,map!()會修改原始對象。python

map()和collect()等價,同理map!()和collect!()等價。算法

arr = [1, 2, 3, 4, 5]
new_arr = arr.map{|a| 2*a}
p new_arr1    # [2, 4, 6, 8, 10]
p arr         # [1, 2, 3, 4, 5]

new_arr1 = arr.map!{|a| a**2}
p arr         # [1, 4, 9, 16, 25]
p new_arr1    # [1, 4, 9, 16, 25]

zip()

arr.zip(arg, ...) → new_ary
arr.zip(arg, ...) {|arr| block} → nil

將0或多個arg數組和arr數組的元素一一對應地合併起來。合併時,數量以arr的元素數量爲準,不足的以nil補足,多餘的元素則忽略。shell

a = [ 4, 5, 6 ]
b = [ 7, 8, 9 ]
[1, 2, 3].zip(a, b)   # [[1,4,7],[2,5,8],[3,6,9]]
[1, 2].zip(a, b)      # [[1, 4, 7], [2, 5, 8]]
a.zip([1, 2], [8])    # [[4,1,8],[5,2,nil],[6,nil,nil]]

若是使用語句塊的方式,那麼每次合併後的子數組將傳遞給語句塊中的變量,而後應用語句塊的邏輯,但注意它返回的結果爲nil。因此,zip()語句塊中的block應當是那些能作實際操做的語句,而不是像一種返回值的方式返回操做後的結果,這樣會丟棄結果。看下面示例:數組

a = [ 4, 5, 6 ]
b = [ 7, 8, 9 ]
[1, 2].zip(a, b)      # [[1, 4, 7], [2, 5, 8]]

[1, 2].zip(a, b) do |x|
  x.reduce(:+)         # (1).不合理
end

[1, 2].zip(a, b) do |x|
  p x.reduce(:+)       # (2).合理
end

sum = 0
[1, 2].zip(a, b) do |x|
  sum += x.reduce(:+)  # (3).合理
end
p sum

首先,上面zip()兩次傳遞到語句塊中的變量分別是[1, 4, 7][2, 5, 8]x.reduce(:+)表示將x容器(此處爲數組)中的元素全都相加。因此,第一次迭代語句塊時,x.reduce(:+)的結果是1+4+7=12,第二次迭代的結果是2+5+8=15。ruby

可是在(1)中,它僅僅只是相加了,加了以後結果就被丟棄了,它不會做爲新數組的元素返回,由於zip()使用語句塊時返回的是nil,而不是新數組。app

因此,在(2)中,對相加以後的結果加了一個p()動做將其輸出,也就是使用了x.reduce的結果,並無丟棄。dom

同理,在(3)中,將相加以後的結果加總到sum上,使得最後sum的值被保留,這裏也使用了x.reduce的結果,並無丟棄。測試


select()和select!()

filter()、filter!()分別等價於select()、select!()。

迭代數組,並從數組中選擇那些符合語句塊中測試條件的元素,最後組成一個新數組。

select()不會修改原始數組對象,select!()會修改原始對象。

arr = [1, 2, 3, 4, 5, 6]
new_arr = arr.select {|a| a > 3}
p new_arr      # [4, 5, 6]
p arr          # [1, 2, 3, 4, 5, 6]

new_arr = arr.select! {|a| a > 3}
p new_arr      # [4, 5, 6]
p arr          # [4, 5, 6]

reject()和reject!()

和select()是相反的行爲,從數組中篩選不知足條件的元素。

reject()不會修改原始數組對象,reject!()會修改原始對象。

arr = [1, 2, 3, 4, 5, 6]
new_arr = arr.reject {|a| a > 3}
p new_arr      # [1, 2, 3]
p arr          # [1, 2, 3, 4, 5, 6]

new_arr = arr.reject! {|a| a > 3}
p new_arr      # [1, 2, 3]
p arr          # [1, 2, 3]

keep_if()

keep_if {|item| block} → ary
keep_if → Enumerator

keep_if()從數組中刪除不知足語句塊中條件的元素,即保留知足條件的元素。

注意原處修改對象

arr = [1, 2, 3, 4, 5, 6]
new_arr = arr.keep_if {|a| a < 4}
p new_arr   # [1, 2, 3]
p arr       # [1, 2, 3]

uniq()和uniq!()

ary.uniq                -> new_ary
ary.uniq {|item| ...}   -> new_ary
ary.uniq!                -> ary or nil
ary.uniq! {|item| ...}   -> ary or nil

對於語句塊格式的語法,將迭代每一個元素,而後根據語句塊中的返回值做爲重複值比較的依據。

對於uniq!(),若是沒有任何重複元素能夠去除,則返回nil,這時原數組不變,這是帶有後綴!但不改變原對象的一個特例。其它狀況這些方法均返回去重後的數組。

a = [ "a", "a", "b", "b", "c" ]
a.uniq   # ["a", "b", "c"], a不變

b = [["student","sam"], ["student","george"], ["teacher","matz"]]
b.uniq {|s| s.first}  # [["student","sam"],["teacher","matz"]],b不變


a = [ "a", "a", "b", "b", "c" ]
a.uniq!   # ["a", "b", "c"],a已變

b = [ "a", "b", "c" ]
b.uniq!   # nil,b不變

c = [["student","sam"], ["student","george"], ["teacher","matz"]]
c.uniq! {|s| s.first}  # [["student","sam"],["teacher","matz"]],c已變

compact()和compact!()

compact! → new_ary
compact! → ary or nil

去除數組中全部nil元素。

帶感嘆號的方法表示原處修改,若是沒有nil元素可去除,則返回nil。

["a",nil,"b",nil,"c",nil].compact #["a","b","c"]

["a",nil,"b",nil,"c"].compact! # ["a","b","c"]
["a","b","c"].compact!         # nil



all()、any()、none()和one()

all? [{ |obj| block } ] → true or false
all?(pattern) → true or false

any? [{ |obj| block } ] → true or false
any?(pattern) → true or false

none? [{ |obj| block } ] → true or false
none?(pattern) → true or false

one? [{ |obj| block } ] → true or false
one?(pattern) → true or false

對於這些方法,均有三種行爲:

  • 當使用語句塊時,將判斷容器中是否全部元素(all)、是否任一元素(any)、是否沒有元素(none)、是否有且只有一個元素(one)知足語句塊中的條件
  • 當不使用語句塊但給定參數時,將使用===的測試符號去判斷容器中是否全部元素(all)、是否任一元素(any)、是否沒有元素(none)、是否有且只有一個元素(one)知足條件
  • 當不使用語句塊且不給定參數時,將判斷容器中是否全部元素(all)、是否任一元素(any)、是否沒有元素(none)、是否有且只有一個元素(one)爲true

須要特別對待的是空數組,雖然空數組自身是一個bool true,但空數組沒有元素

  • 對於all(),空數組表示全部元素都爲true,由於它根本沒元素,因此返回true
  • 對於any(),空數組表示沒有元素爲true,由於它根本沒元素,因此返回false
  • 對於none(),空數組表示沒有元素爲true,由於它根本沒元素,因此返回true
  • 對於one(),空數組沒有一個元素爲true,由於它根本沒元素,因此返回false
# all()
%w[ant bear cat].all? { |word| word.length >= 3 } # true
%w[ant bear cat].all? { |word| word.length >= 4 } # false
%w[ant bear cat].all?(/t/)                        # false
[1, 2i, 3.14].all?(Numeric)                       # true
[nil, true, 99].all?                              # false
[].all?                                           # true
# any()
%w[ant bear cat].any? { |word| word.length >= 3 } # true
%w[ant bear cat].any? { |word| word.length >= 4 } # true
%w[ant bear cat].any?(/d/)                        # false
[nil, true, 99].any?(Integer)                     # true
[nil, true, 99].any?                              # true
[].any?                                           # false
# none()
%w{ant bear cat}.none? {|word| word.length == 5} # true
%w{ant bear cat}.none? {|word| word.length >= 4} # false
%w{ant bear cat}.none?(/d/)                      # true
[1, 3.14, 42].none?(Float)                       # false
[].none?                                         # true
[nil].none?                                      # true
[nil, false].none?                               # true
[nil, false, true].none?                         # false
# one()
%w{ant bear cat}.one? {|word| word.length == 4}  # true
%w{ant bear cat}.one? {|word| word.length > 4}   # false
%w{ant bear cat}.one? {|word| word.length < 4}   # false
%w{ant bear cat}.one?(/t/)                         # false
[ nil, true, 99 ].one?                             # false
[ nil, true, false ].one?                          # true
[ nil, true, 99 ].one?(Integer)                    # true
[].one?                                            # false

count()

計算數組中知足條件的元素個數。

count → int
count(obj) → int
count {|item| block} → int
  • 無參數時,計算數組全部元素個數
  • 有參數時,計算數組中等於obj對象的元素個數,使用==進行等值測試
  • 語句塊時,迭代數組每一個元素,並計算符合語句塊條件的元素個數
ary = [1, 2, 4, 2]
ary.count                  # 4,數組元素個數
ary.count(2)               # 2,等於2的元素個數
ary.count {|x| x%2 == 0}   # 3,偶元素個數


length()和size()

二者等價,均返回數組元素個數。和不帶參數的count()等價。

cycle()

cycle(n=nil) {|obj| block} → nil
cycle(n=nil) → Enumerator

迭代數組每一個元素並調用語句塊,而後循環n次整個數組的迭代過程(注意是按整個數組計算次數,而不是對每一個元素,因此是先迭代完一次數組,再循環迭代第二次數組,以此類推)。

若是不給參數或參數爲nil,則無限循環迭代。

a = ["a", "b", "c"]
a.cycle {|x| puts x}     # a,b,c,a,b,c, ... forever
a.cycle(2) {|x| puts x}  # a,b,c,a,b,c

delete()

ary.delete(obj)            -> item or nil
ary.delete(obj) {block}    -> item or result of block

刪除數組中全部等於obj的對象,返回最後被刪除的元素。若是沒有元素可刪除,則返回nil。若是使用了語句塊,則在無元素可刪除的狀況下返回語句塊的結果而不是nil。至關於語句塊提供了默認值來替代nil返回值。

注意原處修改。

a = [ "a", "b", "b", "b", "c" ]
a.delete("b")                   # "b"
a                               # ["a", "c"]
a.delete("z")                   # nil
a.delete("z") {"not found"}     # "not found"

delete_at()

delete_at(index) → obj or nil

刪除數組中指定索引位置處的元素,並返回該元素,若是索引越界則返回nil。

注意原處修改。

a = ["ant", "bat", "cat", "dog"]
a.delete_at(2)    # "cat"
a                 # ["ant", "bat", "dog"]
a.delete_at(99)   # nil

delete_if()

delete_if {|item| block} → ary
delete_if → Enumerator

delete_if()從數組中刪除知足語句塊中條件的元素。

注意原處修改。

arr = [1, 2, 3, 4, 5, 6]
new_arr = arr.delete_if {|a| a < 4}
p new_arr   # [4, 5, 6]
p arr       # [4, 5, 6]

dig()

dig(idx, ...) → object

根據給定的索引idx去提取數組中的元素。這主要用於從多層嵌套的數組取元素,特別是層次複雜的數組。

a = [[1, [2, 3]]]

a.dig(0, 1, 1)                  # 3
a.dig(1, 2, 3)                  # nil
a.dig(0, 0, 0)                  # TypeError: Integer does not have #dig method
[42, {foo: :bar}].dig(1, :foo)  # :bar

其中:

dig(0,1,1)表示首先從數組a中取idx=0的元素,即取得[1,[2,3]],再取得idx=1的元素,即[2,3],最後再取得idx=1的元素,即3。

dig(1,2,3)在第1次取元素的過程越界,由於[[1, [2, 3]]]只有一個元素。

dig(0,0,0)第一次取得[1, [2, 3]],第二次取得1,由於1再也不是數組,因此第三次取元素時報錯。


first()和last()

first → obj or nil
first(n) → new_ary

last → obj or nil
last(n) → new_ary

取數組頭部或數組尾部的一個或n個元素,但不修改原數組。

  • 未給定參數時,表示取頭或尾的一個元素,數組爲空時返回nil
  • 給定參數時,表示取頭或尾的n個元素,數組元素不夠取時則能取多少返回多少,而數組爲空時一個都取不到,因此返回空數組
a = %w(a b c d)

a.first      # "a"
a.last       # "d"
a.first(2)   # ["a", "b"]
a.last(2)    # ["c", "d"]
a.first(10)  # ["a", "b", "c", "d"]
a.last(10)   # ["a", "b", "c", "d"]
[].first     # nil
[].first(2)  # []


drop()和take()

drop(n) → new_ary
take(n) → new_ary

take()從數組頭部返回前n個元素。

drop()從數組頭部刪除前n個元素,而後將剩下的元素做爲新數組返回。

原數組不變。

# drop()
a = ["a", "b", "c"]
a.drop(2)    # 返回["c"],a不變

# take()
a = [1, 2, 3, 4, 5, 0]
a.take(3)    # [1, 2, 3]


drop_while()和take_while()

drop_while {|obj| block} → new_ary
drop_while → Enumerator

take_while {|obj| block} → new_ary
take_while → Enumerator

take_while()從數組頭部開始迭代元素,直到遇到不滿組語句塊中條件的元素中止迭代,而後返回全部已迭代的知足條件的元素。

drop_while()從數組頭部開始迭代元素,一直刪除元素直到遇到不知足語句塊中條件的元素中止迭代。而後將剩下的元素做爲新數組返回。

注意,不是原處修改。

# drop_while()
arr = [1, 2, 3, 4, 5, 6]
new_arr = arr.drop_while {|a| a<4}
p new_arr   # [4, 5, 6]
p arr       # [1, 2, 3, 4, 5, 6]

# take_while()
a = [1, 2, 3, 4, 5, 0]
a.take_while {|i| i < 3}    #=> [1, 2]

fetch()

fetch(index) → obj
fetch(index, default) → obj
fetch(index) {|index| block} → obj

按照給定index獲取數組中的元素。若是index越界,則根據三種不一樣形式進行處理:

  • 沒有給第二個參數、沒有使用語句塊時,直接報錯
  • 給了第二個參數時,index越界時將返回該第二個參數值做爲默認值
  • 使用了語句塊時,index越界時將執行語句塊中內容,並將index傳遞給語句塊變量
a = [ 11, 22, 33, 44 ]
a.fetch(1)               #=> 22
a.fetch(-1)              #=> 44
a.fetch(4, 'cat')        #=> "cat"
a.fetch(100) {|i| puts "#{i} is out of bounds"}
                         #=> "100 is out of bounds"

fill()

# 原處修改
fill(obj) → ary
fill(obj, start [, length]) → ary
fill(obj, range) → ary

fill {|index| block} → ary
fill(start [, length]) {|index| block} → ary
fill(range) {|index| block} → ary

前三種形式,據使用obj值替換數組中給定範圍內元素的值:

  • fill(obj):使用obj替換全部元素
  • fill(obj, start [, len]):替換從start開始,長度len個元素,沒有給len則替換後面全部元素
  • fill(obj, range):替換range所指定的範圍元素

後三種形式,將傳遞數組索引到語句塊,且給定範圍內的元素將使用語句塊的計算結果進行替換,範圍以外的則保留使用索引值元素。

a = [ "a", "b", "c", "d" ]
a.fill("x")              # ["x", "x", "x", "x"]
a.fill("z", 2)           # ["x", "x", "z", "z"]
a.fill("y", 0..1)        # ["y", "y", "z", "z"]
a.fill {|i| i*i}         # [0, 1, 4, 9]
a.fill(-2) {|i| i*i*i}   # [0, 1, 8, 27]



pop()、push()和append()

push(obj, ...) → ary
append(obj, ...) → ary

pop → obj or nil
pop(n) → new_ary

注意原處修改。

  • push():將給定一個或多個元素追加到數組尾部,由於返回數組自身,因此能夠鏈式追加
  • append():等價於push()
  • pop():從數組尾部移除並返回1個或n個元素(此時做爲數組返回),若是數組爲空則返回nil。等價於slice!(-n,n)
# push()、append()
a = [ "a", "b", "c" ]
a.push("d","e","f")     # %w[a b c d e f]
[1,2,3].push(4).push(5) # [1,2,3,4,5]
# pop()
a = [ "a", "b", "c", "d" ]
a.pop     # "d"
a.pop(2)  # ["b", "c"]
a         # ["a"]



shift()、unshift()和prepend()

unshift(obj, ...) → ary
prepend(obj, ...) → ary

shift → obj or nil
shift(n) → new_ary

注意原處修改。

  • unshift():向數組頭部插入一個或多個元素,會致使整個數組原有元素後移
  • prepend():等價於unshift()
  • shift():從數組頭部移除並返回1個或n個元素(此時以數組方式返回),會致使整個數組原有元素前移。若是數組爲空則返回nil。等價於slice!(0,n)
# unshift、prepend()
a = [ "b", "c", "d" ]
a.unshift("a")   #=> ["a", "b", "c", "d"]
a.unshift(1, 2)  #=> [ 1, 2, "a", "b", "c", "d"]
# shift
args = ["-m", "-q", "filename"]
args.shift     # "-m"
args           # ["-q", "filename"]

args = [ "-m", "-q", "filename" ]
args.shift(2)  #=> ["-m", "-q"]
args           #=> ["filename"]

flatten()和flatten!()

flatten → new_ary 
flatten(level) → new_ary

flatten! → ary or nil
flatten!(level) → ary or nil

將多層次的嵌套數組壓平,level能夠指定最多壓到那一層。對於帶感嘆號後綴的方法,若是數組沒法再壓或層數不夠,則返回nil。

s = [ 1, 2, 3 ]           # [1,2,3]
t = [ 4, 5, 6, [7, 8] ]   # [4,5,6,[7,8]]
a = [ s, t, 9, 10 ]       # [[1,2,3],[4,5,6,[7,8]],9,10]
a.flatten                 # [1,2,3,4,5,6,7,8,9,10]
a = [ 1, 2, [3, [4, 5] ] ]
a.flatten(1)              # [1, 2, 3, [4, 5]]

a = [ 1, 2, [3, [4, 5] ] ]
a.flatten!   #=> [1, 2, 3, 4, 5]
a.flatten!   #=> nil,已經壓平了
a            #=> [1, 2, 3, 4, 5]
a = [ 1, 2, [3, [4, 5] ] ]
a.flatten!(1) #=> [1, 2, 3, [4, 5]]
a.flatten!(1) #=> [1, 2, 3, 4, 5]
a.flatten!(1) #=> nil

hash()

計算數組的hash值。執行eql?()的比較時,其比較依據就是hash值。

[1, 2].hash    # 2027605168499122706
[1, 2.0].hash  # 3393919734812826294

include?()

include?(object) → true or false

判斷數組中是否包含某元素。判斷的依據是使用==比較。

a = [ "a", "b", "c" ]
a.include?("b")       # true
a.include?("z")       # false
[1, 2.0].include?(2)  # true

index()和rindex()

index(obj) → int or nil
index {|item| block} → int or nil
index → Enumerator

rindex(obj) → int or nil
rindex {|item| block} → int or nil
rindex → Enumerator

搜索數組中知足條件的元素並返回其索引位置,搜索不到將返回nil。

# index(obj)、rindex(obj)
# 返回數組中第一個、最後一個等於obj的元素位置
# 使用"=="進行測試
a = [ "a", "b", "c" ]
p a.index("b")              # 1
p a.index("z")              # nil
p a.index {|x| x == "b"}    # 1

# (r)index {|item| block}
# 返回第一個/最後一個知足語句塊中條件的元素位置
a = [ "a", "b", "b", "b", "c" ]
p a.rindex("b")             # 3
p a.rindex("z")             # nil
p a.rindex {|x| x == "b"}   # 3


initialize_copy()和replace()

二者等價。

initialize_copy(other_ary) → ary

使用other_ary數組替換當前數組中的元素,並按需收縮、擴展。

注意原處修改。

a = %w(a b c d e)     # ["a", "b", "c", "d", "e"]
a.replace(%w[x y z])  # ["x", "y", "z"]
a                     # ["x", "y", "z"]

join()

join(separator=$,) → str

將數組各元素經過鏈接符鏈接起來,轉換成字符串返回。

不給sep時默認以$,做爲鏈接符,若是$,爲nil(默認就是nil),則默認使用空字符進行鏈接。

嵌套數組會遞歸鏈接。

鏈接符必須是字符串類型。

實際上,join()的過程是:將數組各元素全都使用to_s轉換成字符串,而後對鏈接符使用to_str轉換成字符串。

["a","b","c"].join        # "abc"
["a","b","c"].join("-")   # "a-b-c"
["a",[1,2,[:x,:y]], "b" ].join("-")   # "a-1-2-x-y-b"

# 數值不能做爲鏈接符,由於它沒有定義to_str
%w(perl shell ruby).join(1) # TypeError


max()和min()

max → obj
max {|a, b| block} → obj
max(n) → array
max(n) {|a, b| block} → array

min → obj
min {|a, b| block} → obj
min(n) → array
min(n) {|a, b| block} → array

無參數、無語句塊的形式,表示從數組中返回最大/最小的元素。何爲最大/最小,只有數組中全部元素都實現了Comparable模塊才容許比較,也就是能使用<=>對數組不一樣元素之間進行比較。

帶語句塊形式的形式,表示將每一個元素傳遞到語句塊以後通過一番處理,而後經過<=>比較獲得返回結果。

帶參數的形式則表示以數組的方式返回最大/最小的n個元素,也就是返回前幾名對象。

ary = %w(albatross dog horse)
ary.max                                   # "horse"
ary.max {|a, b| a.length <=> b.length}    # "albatross"
ary.max {|a, b| b.length <=> a.length}    # "dog"

ary = %w[albatross dog horse]
ary.max(2)                                # ["horse", "dog"]
ary.max(2){|a, b| a.length <=> b.length}  # ["albatross","horse"]
ary = %w(albatross dog horse)
a = ary.max do |a, b|
  x=a.length
  y=b.length
  y <=> x
end


permutation()和combination()

permutation {|p| block} → ary
permutation → Enumerator
permutation(n) {|p| block} → ary
permutation(n) → Enumerator

combination(n) {|c| block} → ary
combination(n) → Enumerator

permutation()對數組的元素進行排列,返回排列後的各數組。

  • 當指定參數n時,則對全部n個元素做排列
  • 當不指定參數n時,則n默認爲數組長度,即對全部元素做排列

combination()對數組做n個元素的組合。

注意,排列、組合的順序不做任何保證。

關於排列和組合的區別:

  • 排列:從n個不一樣的元素中,取r個不重複的元素,按次序排列,稱爲從n箇中取r個的無重複排列
  • 組合:從n個不一樣的元素中,取r個不重複的元素,組成一個子集,而不考慮其元素的順序,稱爲從n箇中取r個的無重組和

看下面的示例便可理解:

# permutation()做排列操做
a = [1, 2, 3]
a.permutation.to_a    # [[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]]
a.permutation(1).to_a # [[1],[2],[3]]
a.permutation(2).to_a # [[1,2],[1,3],[2,1],[2,3],[3,1],[3,2]]
a.permutation(3).to_a # [[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]]
a.permutation(0).to_a # [[]] # one permutation of length 0
a.permutation(4).to_a # []   # no permutations of length 4
# combination()做組合操做
a = [1, 2, 3, 4]
a.combination(1).to_a  # [[1],[2],[3],[4]]
a.combination(2).to_a  # [[1,2],[1,3],[1,4],[2,3],[2,4],[3,4]]
a.combination(3).to_a  # [[1,2,3],[1,2,4],[1,3,4],[2,3,4]]
a.combination(4).to_a  # [[1,2,3,4]]
a.combination(0).to_a  # [[]] # one combination of length 0
a.combination(5).to_a  # []   # no combinations of length 5

當使用了語句塊時,每一個排列後的子數組將傳遞給語句塊的變量。

a = [1, 2, 3, 4]
a.combination(3) {|x| p x << "z" }
## 輸出:
## [1, 2, 3, "z"]
## [1, 2, 4, "z"]
## [1, 3, 4, "z"]
## [2, 3, 4, "z"]


repeated_combination()和repeated_permutation()

repeated_combination(n) {|c| block} → ary
repeated_combination(n) → Enumerator

repeated_permutation(n) {|p| block} → ary
repeated_permutation(n) → Enumerator

重複n個數組自身,並對這n個數組進行排列操做、組合操做。看示例便可明白。

# repeated_combination()
a = [1, 2, 3]
a.repeated_combination(1).to_a  # [[1], [2], [3]]
a.repeated_combination(2).to_a  # [[1,1],[1,2],[1,3],[2,2],[2,3],[3,3]]
a.repeated_combination(3).to_a  # [[1,1,1],[1,1,2],[1,1,3],[1,2,2],[1,2,3],
                                #    [1,3,3],[2,2,2],[2,2,3],[2,3,3],[3,3,3]]
a.repeated_combination(4).to_a  # [[1,1,1,1],[1,1,1,2],[1,1,1,3],[1,1,2,2],[1,1,2,3],
                                #    [1,1,3,3],[1,2,2,2],[1,2,2,3],[1,2,3,3],[1,3,3,3],
                                #    [2,2,2,2],[2,2,2,3],[2,2,3,3],[2,3,3,3],[3,3,3,3]]
a.repeated_combination(0).to_a  # [[]] # one combination of length 0
# repeated_permutation()
a = [1, 2]
a.repeated_permutation(1).to_a  # [[1], [2]]
a.repeated_permutation(2).to_a  # [[1,1],[1,2],[2,1],[2,2]]
a.repeated_permutation(3).to_a  # [[1,1,1],[1,1,2],[1,2,1],[1,2,2],
                                #    [2,1,1],[2,1,2],[2,2,1],[2,2,2]]
a.repeated_permutation(0).to_a  # [[]] # one permutation of length 0

product()

product(other_ary, ...) → new_ary
product(other_ary, ...) {|p| block} → ary

將數組和other_ary的各元素進行組合後返回。

若是使用了語句塊,則每一個組合後的子數組都傳遞給語句塊,並返回數組自身(即a.product() {}時返回a)。

[1,2,3].product([4,5])     # [[1,4],[1,5],[2,4],[2,5],[3,4],[3,5]]
[1,2].product([1,2])       # [[1,1],[1,2],[2,1],[2,2]]
[1,2].product([3,4],[5,6]) # [[1,3,5],[1,3,6],[1,4,5],[1,4,6],
                           #    [2,3,5],[2,3,6],[2,4,5],[2,4,6]]
[1,2].product()            # [[1],[2]]
[1,2].product([])          # []
# 使用語句塊形式
a = [1,2,3]
sub_a = a.product([4,5]) {|x| p x}
p sub_a

## 輸出:
=begin
[1, 4]
[1, 5]
[2, 4]
[2, 5]
[3, 4]
[3, 5]
[1, 2, 3]
=end

rotate()和rotate!()

rotate(count=1) → new_ary
rotate!(count=1) → ary

轉動數組,使得count位置處的元素做爲新數組的第一個元素。帶感嘆號表示原處修改。

a = [ "a", "b", "c", "d" ]
a.rotate         # ["b", "c", "d", "a"]
a                # ["a", "b", "c", "d"]
a.rotate(2)      # ["c", "d", "a", "b"]
a.rotate(-3)     # ["b", "c", "d", "a"]

a = [ "a", "b", "c", "d" ]
a.rotate!        # ["b", "c", "d", "a"]
a                # ["b", "c", "d", "a"]
a.rotate!(2)     # ["d", "a", "b", "c"]
a.rotate!(-3)    # ["a", "b", "c", "d"]

transpos()

transpose → new_ary

若是是多維數組,則返回行列轉換後的新數組。若是元素個數不一致,則直接報錯。

a = [[1,2], [3,4], [5,6]]
a.transpose   # [[1, 3, 5], [2, 4, 6]]

[[1,2,3],[3,4],[5,6]].transpose # IndexError

simple()

sample → obj
sample(random: rng) → obj
sample(n) → new_ary
sample(n, random: rng) → new_ary

從數組中隨機選擇一個或n個元素。選擇隨機元素的方式是使用隨機的索引進行選取。若是選擇多個隨機元素,則選擇隨機元素的索引位置會保證惟一性,但仍然可能會選中重複元素,由於數組自身可能會包含重複元素。

參數rng表示指定生成索引隨機數的生成器。

當爲空數組時,第一種形式返回nil,第二種形式返回空數組。

a = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
a.sample         # 7
a.sample(4)      # [6, 4, 2, 5]
a.sample(random: Random.new(1))     # 6
a.sample(4, random: Random.new(1))  # [6, 10, 9, 2]

shuffle()和shuffle!()

shuffle → new_ary
shuffle(random: rng) → new_ary

shuffle! → ary
shuffle!(random: rng) → ary

打亂數組元素並返回。感嘆號後綴表示原處修改。

rng參數指定生成隨機數的生塵器。

# shuffle()
a = [ 1, 2, 3 ]           # [1, 2, 3]
a.shuffle                 # [2, 3, 1]
a                         # [1, 2, 3]

a.shuffle(random: Random.new(1))  # [1, 3, 2]

# shuffle!()
a = [ 1, 2, 3 ]           # [1, 2, 3]
a.shuffle!                # [2, 3, 1]
a                         # [2, 3, 1]

a.shuffle!(random: Random.new(1))  # [1, 3, 2]

sum()

sum(init=0) → number
sum(init=0) {|e| expr } → number

返回各元素加法操做之和。例如[e1, e2, e3].sum返回init + e1 + e2 + e3

若是使用了語句塊,則在相加以前,先對各元素執行語句塊。

若是數組爲空,則返回init參數值。

[].sum                             # 0
[].sum(0.0)                        # 0.0
[1, 2, 3].sum                      # 6
[3, 5.5].sum                       # 8.5
[2.5, 3.0].sum(0.0) {|e| e * e }   # 15.25
[Object.new].sum                   # TypeError

不只限於能夠執行數值相加操做,只要經過init參數顯式指明初始值類型便可:

["a", "b", "c"].sum("")            # "abc"
[[1], [[2]], [3]].sum([])          # [1, [2], 3]

可是,join()flatten()都比上述方式運行的更快。

["a", "b", "c"].join               # "abc"
[[1], [[2]], [3]].flatten(1)       # [1, [2], 3]

reverse()和reverse!()

reverse → new_ary
reverse! → ary

將數組元素反轉。帶感嘆號表示原處反轉。

# reverse()
["a","b","c"].reverse   # ["c","b", a"]
[1].reverse             # [1]

# reverse!()
a = ["a","b","c"]
a.reverse!       # ["c","b","a"]
a                # ["c","b","a"]

reverse_each()

reverse_each {|item| block} → ary
reverse_each → Enumerator

相似於each(),但反向迭代,即從數組尾部開始迭代。

a = [ "a", "b", "c" ]
a.reverse_each {|x| print x," "} # 輸出c b a

sort()和sort!()

sort → new_ary
sort {|a, b| block} → new_ary

sort! → ary
sort! {|a, b| block} → ary

對數組元素進行排序,而後返回。帶感嘆號後綴表示原處修改。

當沒有使用語句塊時,排序依據是對各元素使用<=>進行比較。

當使用了語句塊時,將根據語句塊中指定的依據進行排序。

當兩元素比較是等值的,那麼將沒法保證誰在前、誰在後。

# sort()
ary = [ "d", "a", "e", "c", "b" ]
ary.sort                     # ["a","b","c","d","e"]
ary.sort {|a, b| a <=> b}    # ["a","b","c","d","e"]
ary.sort {|a, b| b <=> a}    # ["e","d","c","b","a"]

# sort!()
ary = [ "d", "a", "e", "c", "b" ]
ary.sort!                     # ["a","b","c","d","e"]
ary.sort! {|a, b| a <=> b}    # ["a","b","c","d","e"]
ary.sort! {|a, b| b <=> a}    # ["e","d","c","b","a"]

sort_by()和sort_by!()

sort_by()取自mix-in的Enumerable。sort_by!()是Array自身所實現的。

sort_by { |obj| block } → array
sort_by → an_enumerator

sort_by! {|obj| block} → ary
sort_by! → Enumerator

按照語句塊中的規則進行排序。默認升序排序。

a = %w(perl shell php python java ruby)

a.sort_by {|a| a.length}
   #=> %w[php java ruby perl shell python]
(a.sort_by {|a| a[-1]}).reverse
   #=> %w[ruby php python perl shell java]

第一個排序語句是按照各元素的長度進行升序排序。

第二個排序語句是按照各元素最後一個字符進行升序排序,而後反轉排序結果。


bsearch()和bserach_index()

bsearch {|x| block } → elem
bsearch_index {|x| block } → int or nil

二者工做機制徹底一致,均用於二分法查找元素,惟一不一樣的在於返回結果。前者返回容器元素,後者返回對應索引。

二分法算法查找過程略。但對於這裏的兩個方法,頗有必要解釋一番。僅以bsearch()方法用法爲例。

首先要求數組是已排序過的,或者說對於語句塊來講是單調的

bsearch()通常有兩種用法:查找單個最小元素(find-minimum)、查找範圍內元素(find-any)。

find-minimum(即查找單個元素時),要求語句塊返回true/false。當返回true,則向左繼續,當返回false,則向右繼續。直到沒有元素,才返回最後一個true元素,或一直都沒有true則返回nil

find-any(即查找範圍元素時),要求語句塊返回負數、正數、0。當返回正數時,向右繼續,當返回負數時,向左繼續,返回0則中止

find-minimum示例1:不等值判斷

a = [-1, 1, 2, 4, 5]

p a.bsearch {|x| x > 2}  # 4

此語句中,語句塊首先從數組中取中間的元素(若是是偶數,好比6個元素,則取第4個元素),此處所取元素值爲2。

將其進行x>2的判斷,返回false,因而向右繼續獲得子數組[4, 5]。再從中取得中間元素5,5大於2返回true。因而向左繼續,取得元素4,4大於2返回true。無法繼續向左,因此返回最後一次爲true的元素,即4。

再自行考慮與小於2(如0)、大於2(如3)的值比較時,整個過程是如何的?

find-minimum示例2:等值判斷

arr_in = [-1, 1, 2, 4, 5]

p arr_in.bsearch { |x| x == -1 }  # nil
p arr_in.bsearch { |x| x == 1 }   # nil
p arr_in.bsearch { |x| x == 2 }   # 2
p arr_in.bsearch { |x| x == 4 }   # nil
p arr_in.bsearch { |x| x == 5 }   # 5

爲何和數組中的元素比較,有些能返回值,有些卻返回nil?

對於x == -1x == 1x == 4的比較。首先取中間元素2,比較結果爲false,因而向右獲得子數組[4, 5],從中取中間元素5,結果爲false,繼續往右,可是沒有元素能夠往右了,並且以前一直沒有true的結果,因此返回nil。

同理對於x == 2的比較。首先取中間元素2,比較結果爲true,因而向左獲得子數組[-1,1],取中間元素1,比較結果爲false,因而向右,但沒有元素了,因而返回最後一次的true,即元素2。

對於x == 5的比較,首先取中間元素2,比較結果爲false,因而向右獲得子數組[4, 5],從中取中間元素5,結果爲true,繼續往左,獲得子數組[4],因而中間元素4與之比較爲false,繼續向右,但向右已沒有元素,因而返回最後一次爲true的元素,即5。

find-any示例3:返回正、負、0的表達式

a = [-1, 1, 2, 4, 5]

a.bsearch {|x| -1 - x}  # -1
a.bsearch {|x| 1 - x}   # 1
a.bsearch {|x| 2 - x}   # 2
a.bsearch {|x| 4 - x}   # 4
a.bsearch {|x| 5 - x}   # 5

a.bsearch {|x| 3 - x}   # nil

對於-1 - x1 - x,首先取中間元素2,返回結果負數,因而向左繼續,獲得子數組[-1, 1],取中間元素1,對於1 - x返回0,因而當即中止並返回,對於-1 - x返回-2繼續向左獲得[-1],取中間元素相減後返回0,因而當即中止並返回-1。

對於2-x,首先取中間元素2,返回結果0,當即中止並返回2。

對於4-x5-x,首先取中間元素2,返回結果爲正數,因此向右繼續取得子數組[4, 5],取中間元素5,對於5-x當即中止並返回,對於4-x獲得負數因而向左取得子數組[4],最後返回0並中止。

而對於3 - x,則首先返回1爲正數,向右取子數組[4, 5],再次返回負數,因而向左取得[4],仍然爲負數,但已無元素可繼續向左,因而返回nil。

find-any示例4:<=>符號的比較

當在bsearch()中使用<=>符號時,必須將待比較值放在左邊,由於<=>的操做符兩邊元素的順序很重要。

a = [-1, 1, 2, 4, 5]

# 待比較值放左邊,參數放右邊
a.bsearch {|x| -1 <=> x}  # -1
a.bsearch {|x| 1 <=> x}   # 1
a.bsearch {|x| 2 <=> x}   # 2
a.bsearch {|x| 4 <=> x}   # 4
a.bsearch {|x| 5 <=> x}   # 5

a.bsearch {|x| 3 <=> x}   # nil

# 待比較值放右邊,參數放左邊
a.bsearch {|x| x <=> -1}   # nil
a.bsearch {|x| x <=> 1}   # nil
a.bsearch {|x| x <=> 2}   # 2
a.bsearch {|x| x <=> 4}   # nil
a.bsearch {|x| x <=> 5}   # nil

首先分析待比較值放左邊,參數放右邊的狀況。

對於-1 <=> x1 <=> x,首先取中間元素2,比較的返回結果爲-1,因而向左繼續取得子數組[-1, 1],繼續取中間元素1,對於1 <=> x所比較的返回結果0,因而當即中止並返回元素1。對於-1 <=> x比較的返回結果-1,因而向左繼續取自數組[-1],最終比較的返回結果爲0,返回-1元素。

對於2 <=> x,第一次取中間元素2就獲得0,當即中止並返回。

對於4 <=> x5 <=> x,首先取中間元素2,比較的返回結果爲1,因而向右繼續取得子數組[4, 5],繼續取中間元素5,對於5 <=> x所比較的返回結果0,因而當即中止並返回元素51。對於4 <=> x比較的返回結果-1,因而向左繼續取自數組[4],最終比較的返回結果爲0,返回4元素。

對於3 <=> x,自行分析。

再分析待比較值放右邊,參數放右邊的狀況。

對於x <=> -1x <=> 1,首先取中間元素2,比較的返回結果爲1,因而向右繼續取得子數組[4, 5],到這已經不用再向後分析了,由於它們都大於待比價的值,使得一直向右取子數組,最終致使返回nil。

對於x <=> 2,第一次取中間元素2就獲得0,當即中止並返回。

對於x <=> 4x <=> 5,首先取中間元素2,比較的返回結果爲-1,因而向右繼續取得子數組[-1, 1],到這已經不用再向後分析了,由於它們都小於於待比價的值,使得一直向左取子數組,最終致使返回nil。

相關文章
相關標籤/搜索