Ruby Enumerator的各類迭代

Enumerator迭代

Mix-in Enumerator得到的迭代方法數組

each_cons()

each_cons(n) { ... } → nil
each_cons(n) → an_enumerator

迭代容器中的每一個元素,都從其開始向後取連續n個元素組成一個數組傳遞到語句塊中。ruby

(1..10).each_cons(3) { |a| p a }
## 輸出:
=begin
[1, 2, 3]
[2, 3, 4]
[3, 4, 5]
[4, 5, 6]
[5, 6, 7]
[6, 7, 8]
[7, 8, 9]
[8, 9, 10]
=end

each_slice()

each_slice(n) { ... } → nil
each_slice(n) → an_enumerator

每次從容器中取出n個元素組成數組傳遞到語句塊中。code

(1..10).each_slice(3) { |a| p a }
## 輸出:
=begin
[1, 2, 3]
[4, 5, 6]
[7, 8, 9]
[10]
=end

each_with_index()

each_with_index { |obj, i| block } → enum
each_with_index → an_enumerator

迭代容器每一個元素,將元素和其對應的index傳遞給語句塊中的兩個變量。對象

hash = Hash.new
%w(cat dog wombat).each_with_index { |item, index|
  hash[item] = index
}
hash   # {"cat"=>0, "dog"=>1, "wombat"=>2}

with_index()

e.with_index(offset = 0) {|(*args), idx| ... }
e.with_index(offset = 0)

迭代容器每一個元素,將元素和對應的index傳遞給語句塊中的兩個變量。能夠指定參數offset,使得傳遞給語句塊的index變量從offset開始(即傳遞每一個原始index加上offset後的值)。默認,offset=0,等價於each_with_index。blog

a = %w(a b c d e)

a.each.with_index do |x,idx|
  p "index: #{idx}, value: #{x}"
end
## 輸出:
=begin
"index: 0, value: a"
"index: 1, value: b"
"index: 2, value: c"
"index: 3, value: d"
"index: 4, value: e"
=end

a.each.with_index(2) do |x,idx|
  p "index: #{idx}, value: #{x}"
end
## 輸出:
=begin
"index: 2, value: a"
"index: 3, value: b"
"index: 4, value: c"
"index: 5, value: d"
"index: 6, value: e"
=end

each_with_object()

each_with_object(obj) { |(*args), memo_obj| ... } → obj
each_with_object(obj) → an_enumerator

實現相似於reject/reduce的功能。迭代每一個元素,而後將元素傳遞給語句塊中的變量,於此同時,還會指定一個obj參數對象做爲memo_obj變量的初始值,最後通過語句塊的操做以後,返回obj最初引用的對象。字符串

必須注意,obj應該傳遞可變對象,並保證在語句塊中沒有改變obj對象的引用,不然each_with_object將老是返回初始值。見下面示例分析。hash

evens = (1..10).each_with_object([]) { |i, a| a << i*2 }
#=> [2, 4, 6, 8, 10, 12, 14, 16, 18, 20]

上面的例子中,迭代Range容器中的每一個元素並將之傳遞給語句塊中的變量i,同時傳遞一個初始空數組對象給語句塊中的變量a,這就像是在語句塊中初始化了一個空數組。而後,每次迭代過程當中都將i乘2後放入數組的尾部。最後返回這個數組對象a。it

再好比下面的例子中,傳遞初始字符串對象"x",兩個語句塊都將每次迭代的字母追加到這個字符串對象的尾部,可是結果卻不一樣。class

a = ("a".."c").each_with_object("x") {|i,str| str += i}
b = ("a".."c").each_with_object("x") {|i,str| str << i}
p a      # "x"
p b      # "xabc"

這是由於,雖然str += i每次都會建立新的對象並賦值給str,使得str從引用原有的字符串對象"x"改變爲引用另外一個新對象,每次迭代都會改變引用目標,使得最後返回時,只能返回最初始的字符串對象"x"。容器

str << i的方式是直接在原字符串上追加字母的,str所引用的對象一直都未改變,最後返回的原始對象也是更改後的。

而對於數值對象來講,它是不可變對象,意味着操做這個對象必定會返回一個新對象,並且下面也使用sum += i的方式,它自己就是返回新對象的。因而,下面的例子將老是返回初始數值對象0。

a = (1..10).each_with_object(0) {|i, sum| sum += i}
p a   # 0

要實現數值相加,可使用reduce/inject()來實現。

a = (1..10).inject(:+)
p a  # 55

a = (1..10).inject {|sum, x| sum + x}
p a  # 55

each_entry()

傳遞容器中每一個元素給語句塊,並從語句塊中yield一個新數組返回。

class Foo
  include Enumerable
  def each
    yield 1
    yield 1, 2
    yield
  end
end
Foo.new.each_entry{ |o| p o }

## 輸出:
=begin
1
[1, 2]
nil
=end
相關文章
相關標籤/搜索