“茴”字的 N 种写法:关于 Ruby Array 与 Enumerable
Ruby, Array, and Enumerable
【词汇量?是的!编程语言也要背单词!】
Array 是最基本的数据结构之一。
对数组的操作,回忆一下,除了 .each
,你还会哪些操作?
对 Array 元素进行处理的操作很常见。 Array 的内置方法提供了基本的操作。然而有些场合这些方法并不够用以实现简单的处理逻辑。 好消息是可以利用 Enumerable 模块提供的方法,而这些方法容易被忽视。
判断必然性与存在性 all?
/ any?
/ none?
/ one?
如何判断一个数组的全部对象满足某一条件?或者任意对象满足某一条件?
用 all?
/ any?
来实现:
’’’ [true, false, 1, 0].all? ‘’’
如判断一个字符串数组的对象是否由小写字母组成:
ary = ['hello', 'world', '123']
# 判断全部满足条件,使用 each 循环
-> (ary) {
ary.each {|s|
return false unless s.match /[a-z]+/
}
return true
}.call(ary)
# map 结合 all?
ary.map {|s| s.match /[a-z]+/ }.all?
# 直接用 all? 判断
ary.all? {|s| s.match /[a-z]+/ }
# 判断任一满足条件,使用 each 循环
-> (ary) {
ary.each {|s|
return true if s.match /[a-z]+/
}
return false
}.call(ary)
# map 结合 any?
ary.map {|s| s.match /[a-z]+/ }.any?
# 直接用 any? 判断
ary.any? {|s| s.match /[a-z]+/ }
包含代码块的调用,使用代码块返回值作真假判断; 不包含传递代码块的调用,直接对数组的元素作真假判断。
先做变换,然后操作 flat_map
collect_concat
each
和 map
方法返回值如果仍为需要合并的数组,使用这个方法来减少一次 flatten 操作。
[1,2,3,4].collect{|n| [n]*n }
# => [[1], [2, 2], [3, 3, 3], [4, 4, 4, 4]]
[1,2,3,4].collect_concat{|n| [n]*n }
# => [1, 2, 2, 3, 3, 3, 4, 4, 4, 4]
数数 count
这个方法的作用很简单。
count
其实还可以接受一个参数或代码块,用于对特定的值或条件作计数。
%w{a b c d a c e}.count('a')
# => 2
%w{a b c d a c e}.count{|x| x > 'b'}
=> 4
遍历查询 find
/ detect
寻找第一个满足条件的值
(1..100).find { |i| i % 5 == 0 and i % 3 == 0 }
切分
切分是一大类方法。
恰当的切分有助于使用合适的数据结构作数据操作。
分块处理 chunk
顾名思义,对数组的元素 分块
。这个方法主要用于分组处理,可以使得逻辑更加清晰。
ary = [3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5]
ary.chunk { |n| n > 3 }.to_a
# => [[false, [3, 1]], [true, [4]], [false, [1]], [true, [5, 9]], [false, [2]], [true, [6, 5]], [false, [3]], [true, [5]]]
分区 partition
根据条件分为两组
(1..6).partition {|v| v % 3 == 0 }
# => [[3, 6], [1, 2, 4, 5]]
each_cons
/ each_slice
适用于对相邻的元素进行操作。
这两个方法都是一次取出 n 个元素。但是取的操作有区别。
each_cons
从第 1 个元素开始去取 n 个元素,下一次从第 2 个元素开始,以此类推。
each_slice
从第 1 个元素开始去取 n 个元素,下一次从第 n + 1 个元素开始,以此类推。
(1..5).each_cons(2).to_a
# => [[1, 2], [2, 3], [3, 4], [4, 5]]
(1..5).each_slice(2).to_a
# => [[1, 2], [3, 4], [5]]
slice_before
/ slice_after
条件满足时,在元素之前或之后进行切分。
(1..10).slice_after{|n| n > 3}.to_a
# => [[1, 2, 3, 4], [5], [6], [7], [8], [9], [10]]
(1..10).slice_before{|n| n > 3}.to_a
# => [[1, 2, 3], [4], [5], [6], [7], [8], [9], [10]]
slice_when
/ chunk_while
(1..10).slice_when{|x,y| x%3 == 0 and y&2 == 0}.to_a
# => [[1, 2, 3], [4, 5, 6, 7, 8, 9, 10]]
(1..10).chunk_while{|x,y| x%3 == 0 and y&2 == 0}.to_a
# => [[1], [2], [3, 4], [5], [6], [7], [8], [9], [10]]