Enumerable和Comparable是Ruby提供的非常重要的模块。这一篇文章主要介绍Enumerable的一些方法。
Enumerable模块提供了遍历,搜索,排序等方法。如果我们自定义的类需要实现这些方法,必须实现一个each方法。如果需要使用max,min,sort等方法,因为这些方法是集合的元素之间的排序,所以该类还必须使用<=>方法。
实例方法
1.all?[{|obj| block}] -> true of false
%w[ant bear cat].all? { |word| word.length >= 3 } #=> true
%w[ant bear cat].all? { |word| word.length >= 4 } #=> false
[nil, true, 99].all? #=> false
2.any?[{|obj| block}] -> true of false
%w[ant bear cat].any? { |word| word.length >= 3 } #=> true
%w[ant bear cat].any? { |word| word.length >= 4 } #=> true
[nil, true, 99].any? #=> true
3.chunk{|elt| ...} -> an_enumerator
OR chunk(initial_state){|elt,state|...} -> an_enumerator
从文档可以看出:该方法将结果返回一个Enumerator实例。这种情况在Enumerable模块中经常可以看到,那么我们就可以完整的使用Enumerator类的方法,由于Enumerator类又继承了Enumerable类的所有方法,所以可以看到对于返回的结果进行了扩充。
下面列出Enumerator的实例方法,在下一篇文章在详细的介绍Enumerator。#each,#each_with_index,#each_with_object,#feed,#inspect,#next,#next_values,#peek,#peek_values,#rewind,#size,#with_index,#with_object
栗子:
[3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5].chunk { |n|
n.even?
}.each { |even, ary|
p [even, ary]
}
#=> [false, [3, 1]]
# [true, [4]]
# [false, [1, 5, 9]]
# [true, [2, 6]]
# [false, [5, 3, 5]]
可以看出来chunk方法返回的Enumerator对象的元素是由(block处理的结果,[元素])组成的
require 'pp'
[1,2,3,4,5,6,7,8].chunk do |n|
n+1
end.each do |n,arr|
pp [n,arr]
end
返回的结果如下:
[2, [1]]
[3, [2]]
[4, [3]]
[5, [4]]
[6, [5]]
[7, [6]]
[8, [7]]
[9, [8]]
此方法非常适合将元素排序,下面的栗子计算了单词的每个开头字母
open('words') do |f|
#首先我们在block中返回words文件中的所有行,没有对其进行任何处理
#输出的结果:是每行的开头字母,以及每行的长度。
f.chunk { |line| line }.each { |ch,line| pp [ch.chr, line[0].length] }
end
4.collect{|obj|block}
OR collect -> an_enumerator
(1..4).collect { |i| i*i } #=> [1, 4, 9, 16]
(1..4).collect { "cat" } #=> ["cat", "cat", "cat", "cat"]
5.collect_concat{|obj| block} -> array
OR collect_concat -> an_enumerator
[1, 2, 3, 4].flat_map { |e| [e, -e] } #=> [1, -1, 2, -2, 3, -3, 4, -4]
[[1, 2], [3, 4]].flat_map { |e| e + [100] } #=> [1, 2, 100, 3, 4, 100]
别名就是flat_map
6.count -> int
OR count(item) -> int
OR count{ |obj| block } -> int
返回集合的数量,如果传递了参数,返回集合中和参数相同元素的个数,如果传递了block,返回block中为真的元素个数
ary = [1, 2, 4, 2]
ary.count #=> 4
ary.count(2) #=> 2
ary.count{ |x| x%2==0 } #=> 3
7.cycle(n=nil) {|obj| block} -> nil
OR cycle(n=nil) -> an_enumerator
a = ["a", "b", "c"]
a.cycle { |x| puts x } # 打印: a, b, c, a, b, c,...无限多个
a.cycle(2) { |x| puts x } # 打印:a, b, c, a, b, c.
8.detect(ifnone=nil){|obj| block} -> obj or nil
OR detect(ifnone=nil) -> an_enumerator
(1..10).detect { |i| i % 5 == 0 and i % 7 == 0 } #=> nil
(1..100).detect { |i| i % 5 == 0 and i % 7 == 0 } #=> 35
当然如果该方法没有返回值时,可以为该方法指定一个默认值:
class Test
def default
'I am default'
end
end
t = Test.new
pp (1..10).detect(t.method(:default)) { |i| i > 10 }
或者
pp (1..10).detect(lambda { "I am default" }) { |i| i > 10 }
9.drop(n) -> array
删除前n项元素,返回剩余元素
a = [1, 2, 3, 4, 5, 0]
a.drop(3) #=> [4, 5, 0]
10.drop_while{|arr| block} -> array
OR drop_while -> an_enumerator
a = [1, 2, 3, 4, 5, 0]
a.drop_while { |i| i < 3 } #=> [3, 4, 5, 0]
11.each_cons(n){...} -> nil
OR each_cons(n) -> an_enumerator
(1..10).each_cons(3) { |a| p a }
# 结果如下
[1, 2, 3]
[2, 3, 4]
[3, 4, 5]
[4, 5, 6]
[5, 6, 7]
[6, 7, 8]
[7, 8, 9]
[8, 9, 10]
12.ench_entry{|obj| block} -> enum
%w(1 2 3 4).each_entry {|x| p x}
13.each_slice(n){...} -> nil
OR each_slice(n) -> an_enumerator
(1..10).each_slice(3) { |a| p a }
# 结果如下
[1, 2, 3]
[4, 5, 6]
[7, 8, 9]
[10]
14.each_with_index(*args){|obj,i| block} -> enum
OR each_with_index(*args) -> an_enumerator
hash = Hash.new
%w(cat dog wombat).each_with_index { |item, index|
hash[item] = index
}
hash #=> {"cat"=>0, "dog"=>1, "wombat"=>2}
15.each_with_object(obj){|(*args), memo_obj|...} -> obj
OR each_with_object(obj) -> an_enumerator
evens = (1..10).each_with_object([]) { |i, a| a << i*2 }
#=> [2, 4, 6, 8, 10, 12, 14, 16, 18, 20]
16.entries -> array
(1..7).to_a #=> [1, 2, 3, 4, 5, 6, 7]
{ 'a'=>1, 'b'=>2, 'c'=>3 }.to_a #=> [["a", 1], ["b", 2], ["c", 3]]
17.find
同detect
18.find_all{|obj| block} -> array
OR find_all -> an_enumerator
(1..10).find_all { |i| i % 3 == 0 } #=> [3, 6, 9]
[1,2,3,4,5].select { |num| num.even? } #=> [2, 4]
19.finde_index(value) -> int or nil
OR finde_index{|obj| block} -> int or nil
(1..10).find_index { |i| i % 5 == 0 and i % 7 == 0 } #=> nil
(1..100).find_index { |i| i % 5 == 0 and i % 7 == 0 } #=> 34
(1..100).find_index(50) #=> 49
20.first -> obj or nil
OR first(n) -> an_array
%w[foo bar baz].first #=> "foo"
%w[foo bar baz].first(2) #=> ["foo", "bar"]
%w[foo bar baz].first(10) #=> ["foo", "bar", "baz"]
[].first #=> nil
21.grep(pattern) -> array
OR grep(pattern) {|obj| block} -> array
(1..100).grep 38..44 #=> [38, 39, 40, 41, 42, 43, 44]
c = IO.constants
c.grep(/SEEK/) #=> [:SEEK_SET, :SEEK_CUR, :SEEK_END]
res = c.grep(/SEEK/) { |v| IO.const_get(v) }
res #=> [0, 1, 2]
22.group_by{|obj| block} -> a_hash
OR group_by -> an_enumerator
(1..6).group_by { |i| i%3 } #=> {0=>[3, 6], 1=>[1, 4], 2=>[2, 5]}
23.include?(obj) -> true or false
IO.constants.include? :SEEK_SET #=> true
IO.constants.include? :SEEK_NO_FURTHER #=> false
24.inject
# Sum some numbers
(5..10).reduce(:+) #=> 45
# Same using a block and inject
(5..10).inject { |sum, n| sum + n } #=> 45
# Multiply some numbers
(5..10).reduce(1, :*) #=> 151200
# Same using a block
(5..10).inject(1) { |product, n| product * n } #=> 151200
# find the longest word
longest = %w{ cat sheep bear }.inject do |memo, word|
memo.length > word.length ? memo : word
end
longest #=> "sheep"
25.none? [{|obj| block}] -> true or false
%w{ant bear cat}.none? { |word| word.length == 5 } #=> true
%w{ant bear cat}.none? { |word| word.length >= 4 } #=> false
[].none? #=> true
[nil].none? #=> true
[nil, false].none? #=> true
26.one? [{|obj| block} -> true or false]
%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
[ nil, true, 99 ].one? #=> false
[ nil, true, false ].one? #=> true
27.partition {|obj| block} -> [true_array, false_array]
分区方法
(1..6).partition { |v| v.even? } #=> [[2, 4, 6], [1, 3, 5]]