本文簡要介紹ruby語言中 Enumerable.slice_before
的用法。
用法
slice_before(pattern) → enumerator
slice_before {|array| ... } → enumerator
使用參數 pattern
,返回一個枚舉器,該枚舉器使用該模式將元素劃分為數組 (“slices”)。如果element === pattern
(或者如果它是第一個元素),則元素開始一個新切片。
a = %w[foo bar fop for baz fob fog bam foy]
e = a.slice_before(/ba/) # => #<Enumerator: ...>
e.each {|array| p array }
輸出:
["foo"]
["bar", "fop", "for"]
["baz", "fob", "fog"]
["bam", "foy"]
使用塊,返回一個枚舉器,該枚舉器使用塊將元素劃分為數組。如果一個元素的塊返回值為真值(或者如果它是第一個元素),則該元素開始一個新切片:
e = (1..20).slice_before {|i| i % 4 == 2 } # => #<Enumerator: ...>
e.each {|array| p array }
輸出:
[1]
[2, 3, 4, 5]
[6, 7, 8, 9]
[10, 11, 12, 13]
[14, 15, 16, 17]
[18, 19, 20]
Enumerator
類和 Enumerable
模塊的其他方法,例如to_a
、map
等,也可以使用。
例如,對ChangeLog 條目的迭代可以實現如下:
# iterate over ChangeLog entries.
open("ChangeLog") { |f|
f.slice_before(/\A\S/).each { |e| pp e }
}
# same as above. block is used instead of pattern argument.
open("ChangeLog") { |f|
f.slice_before { |line| /\A\S/ === line }.each { |e| pp e }
}
“svn proplist -R”為每個文件生成多行輸出。它們可以按如下方式分塊:
IO.popen([{"LC_ALL"=>"C"}, "svn", "proplist", "-R"]) { |f|
f.lines.slice_before(/\AProp/).each { |lines| p lines }
}
#=> ["Properties on '.':\n", " svn:ignore\n", " svk:merge\n"]
# ["Properties on 'goruby.c':\n", " svn:eol-style\n"]
# ["Properties on 'complex.c':\n", " svn:mime-type\n", " svn:eol-style\n"]
# ["Properties on 'regparse.c':\n", " svn:eol-style\n"]
# ...
如果塊需要維護多個元素的狀態,可以使用局部變量。例如,可以按如下方式壓縮三個或更多連續遞增的數字(請參閱chunk_while
以獲得更好的方法):
a = [0, 2, 3, 4, 6, 7, 9]
prev = a[0]
p a.slice_before { |e|
prev, prev2 = e, prev
prev2 + 1 != e
}.map { |es|
es.length <= 2 ? es.join(",") : "#{es.first}-#{es.last}"
}.join(",")
#=> "0,2-4,6,7,9"
但是,如果結果枚舉器被枚舉兩次或更多,則應謹慎使用局部變量。應該為每個枚舉初始化局部變量。 Enumerator.new
可以用來做。
# Word wrapping. This assumes all characters have same width.
def wordwrap(words, maxwidth)
Enumerator.new {|y|
# cols is initialized in Enumerator.new.
cols = 0
words.slice_before { |w|
cols += 1 if cols != 0
cols += w.length
if maxwidth < cols
cols = w.length
true
else
false
end
}.each {|ws| y.yield ws }
}
end
text = (1..20).to_a.join(" ")
enum = wordwrap(text.split(/\s+/), 10)
puts "-"*10
enum.each { |ws| puts ws.join(" ") } # first enumeration.
puts "-"*10
enum.each { |ws| puts ws.join(" ") } # second enumeration generates same result as the first.
puts "-"*10
#=> ----------
# 1 2 3 4 5
# 6 7 8 9 10
# 11 12 13
# 14 15 16
# 17 18 19
# 20
# ----------
# 1 2 3 4 5
# 6 7 8 9 10
# 11 12 13
# 14 15 16
# 17 18 19
# 20
# ----------
mbox 包含一係列以 Unix From 行開頭的郵件。因此,每封郵件都可以在 Unix From 行之前按切片提取。
# parse mbox
open("mbox") { |f|
f.slice_before { |line|
line.start_with? "From "
}.each { |mail|
unix_from = mail.shift
i = mail.index("\n")
header = mail[0...i]
body = mail[(i+1)..-1]
body.pop if body.last == "\n"
fields = header.slice_before { |line| !" \t".include?(line[0]) }.to_a
p unix_from
pp fields
pp body
}
}
# split mails in mbox (slice before Unix From line after an empty line)
open("mbox") { |f|
emp = true
f.slice_before { |line|
prevemp = emp
emp = line == "\n"
prevemp && line.start_with?("From ")
}.each { |mail|
mail.pop if mail.last == "\n"
pp mail
}
}
相關用法
- Ruby Enumerable.slice_after用法及代碼示例
- Ruby Enumerable.slice_when用法及代碼示例
- Ruby Enumerable.sort用法及代碼示例
- Ruby Enumerable.sort_by用法及代碼示例
- Ruby Enumerable.sum用法及代碼示例
- Ruby Enumerable.select用法及代碼示例
- Ruby Enumerable.any?用法及代碼示例
- Ruby Enumerable.uniq用法及代碼示例
- Ruby Enumerable.find_all用法及代碼示例
- Ruby Enumerable.max用法及代碼示例
- Ruby Enumerable.map用法及代碼示例
- Ruby Enumerable.min_by用法及代碼示例
- Ruby Enumerable.find_index用法及代碼示例
- Ruby Enumerable.minmax用法及代碼示例
- Ruby Enumerable.drop用法及代碼示例
- Ruby Enumerable.member?用法及代碼示例
- Ruby Enumerable.each_cons用法及代碼示例
- Ruby Enumerable.entries用法及代碼示例
- Ruby Enumerable.flat_map用法及代碼示例
- Ruby Enumerable.reject用法及代碼示例
- Ruby Enumerable.each_with_index用法及代碼示例
- Ruby Enumerable.filter_map用法及代碼示例
- Ruby Enumerable.all?用法及代碼示例
- Ruby Enumerable.take用法及代碼示例
- Ruby Enumerable.reduce用法及代碼示例
注:本文由純淨天空篩選整理自ruby-lang.org大神的英文原創作品 Enumerable.slice_before。非經特殊聲明,原始代碼版權歸原作者所有,本譯文未經允許或授權,請勿轉載或複製。