您最喜欢的ruby集合的代码片段是什么?优选地,它们应该是您的发现,具有表现力,可读性,并为您的编码实践带来一些乐趣。
数组中的模式匹配(用于局部变量和参数):
(a, b), c = [[:a, :b], :c]
[a,b,c]
=> [:a, :b, :c]
(a,), = [[:a]]
a
=> :a
从非数组分配到多个变量:
abc, a, b =* "abc".match(/(a)(b)./)
=> ["abc", "a", "b"]
nil1, =* "abc".match(/xyz/)
=> []
使用相同的表达式初始化数组元素:
5.times.map { 1 }
=> [1,1,1,1]
Array.new(5) { 1 }
=> [1,1,1,1,1]
使用相同的值初始化数组:
[2]*5
=>[2,2,2,2,2]
Array.new 5, 2
=>[2,2,2,2,2]
数组的Sum元素:
[1,2,3].reduce(0, &:+)
=> 6
查找符合条件的所有索引:
a.each_with_index.find_all { |e, i| some_predicate(e) }.map(&:last)
替代CSS类:
(1..4).zip(%w[cls1 cls2].cycle)
=> [[1, "cls1"], [2, "cls2"], [3, "cls1"], [4, "cls2"]]
解链:
keys, values = {a: 1, b: 2}.to_a.transpose
keys
=> [:a, :b]
探索字符串的布尔成员方法:
"".methods.sort.grep(/\?/)
探索特定于字符串的方法:
"".methods.sort - [].methods
答案 0 :(得分:2)
带有记忆的懒惰斐波纳契系列,取自Neeraj Singh:
fibs = { 0 => 0, 1 => 1 }.tap do |fibs|
fibs.default_proc = ->(fibs, n) { fibs[n] = fibs[n-1] + fibs[n-2] }
end
fibs.take(10).map(&:last).each(&method(:puts))
计数排序的实现:
module Enumerable
def counting_sort(k)
reduce(Array.new(k+1, 0)) {|counting, n| counting.tap { counting[n] += 1 }}.
map.with_index {|count, n| [n] * count }.flatten
end
end
sum
又名前缀sum:
module Enumerable
def scan(initial=nil, sym=nil, &block)
args = if initial then [initial] else [] end
unless block_given?
args, sym, initial = [], initial, first unless sym
block = ->(acc, el) { acc.send(sym, el) }
end
[initial || first].tap {|res|
reduce(*args) {|acc, el|
block.(acc, el).tap {|e|
res << e
}
}
}
end
end
在这里,我尝试了Hash#each
生成KeyValuePair
s而不是两个元素Array
s。令人惊讶的是,在做了这样一个残酷的猴子补丁后,仍然的代码有多少。是的,鸭子打字!
class Hash
KeyValuePair = Struct.new(:key, :value) do
def to_ary
return key, value
end
end
old_each = instance_method(:each)
define_method(:each) do |&blk|
old_each.bind(self).() do |k, v|
blk.(KeyValuePair.new(k, v))
end
end
end
我一直在玩的东西是让Enumerable#===
执行递归结构模式匹配。我不知道这是否有用。我甚至不知道它是否真的有效。
module Enumerable
def ===(other)
all? {|el|
next true if el.nil?
begin
other.any? {|other_el| el === other_el }
rescue NoMethodError => e
raise unless e.message =~ /any\?/
el === other
end
}
end
end
我最近玩弄的另一件事是重新实现Enumerable
中的所有方法,但使用reduce
代替each
作为基础。在这种情况下,我知道它实际上无法正常工作。
module Enumerable
def all?
return reduce(true) {|res, el| break false unless res; res && el } unless block_given?
reduce(true) {|res, el| break false unless res; res && yield(el) }
end
def any?
return reduce(false) {|res, el| break true if res || el } unless block_given?
reduce(false) {|res, el| break true if res || yield(el) }
end
def collect
reduce([]) {|res, el| res << yield(el) }
end
alias_method :map, :collect
def count(item=undefined = Object.new)
return reduce(0) {|res, el| res + 1 if el == item } unless undefined.equal?(item)
unless block_given?
return size if respond_to? :size
return reduce(0) {|res, el| res + 1 }
end
reduce(0) {|res, el| res + 1 if yield el }
end
def detect(ifnone=nil)
reduce(ifnone) {|res, el| if yield el then el end unless res }
end
alias_method :find, :detect
def drop(n=1)
reduce([]) {|res, el| res.tap { res << el unless n -= 1 >= 0 }}
end
def drop_while
reduce([]) {|res, el| res.tap { res << el unless yield el }}
end
def each
tap { reduce(nil) {|_, el| yield el }}
end
def each_with_index
tap { reduce(-1) {|i, el| (i+1).tap {|i| yield el, i }}}
end
def find_all
reduce([]) {|res, el| res.tap {|res| res << el if yield el }}
end
alias_method :select, :find_all
def find_index(item=undefined = Object.new)
return reduce(-1) {|res, el| break res + 1 if el == item } unless undefined.equals?(item)
reduce(-1) {|res, el| break res + 1 if yield el }
end
def grep(pattern)
return reduce([]) {|res, el| res.tap {|res| res << el if pattern === el }} unless block_given?
reduce([]) {|res, el| res.tap {|res| res << yield(el) if pattern === el }}
end
def group_by
reduce(Hash.new {|hsh, key| hsh[key] = [] }) {|res, el| res.tap { res[yield el] = el }}
end
def include?(obj)
reduce(false) {|res, el| break true if res || el == obj }
end
def reject
reduce([]) {|res, el| res.tap {|res| res << el unless yield el }}
end
end
答案 1 :(得分:1)
从数组初始化多个值:
a = [1,2,3]
b, *c = a
assert_equal [b, c], [1, [2,3]]
d, = a
assert_equal d, a[0]
答案 2 :(得分:0)
我自己的:
使用相同的表达式初始化数组元素:
5.times.map { some_expression }
使用相同的值初始化数组:
[value]*5
数组的Sum元素:
[1,2,3].reduce(0, &:+)
查找符合条件的所有索引:
a.each_with_index.find_all { |e, i| some_predicate(e) }.map(&:last)
答案 3 :(得分:0)
不是真正的片段,但我喜欢这些通用结构(我只展示了如何使用它们,实现很容易在网上找到)。
转换数组 - &gt;哈希(to_hash
或mash
,想法是一样的,请参阅 Facets 实现):
>> [1, 2, 3].mash { |k| [k, 2*k] }
=> {1=>2, 2=>4, 3=>6}
地图+选择/检测:您想要制作地图并仅获取第一个结果(因此map { ... }.first
效率低下):
>> [1, 2, 3].map_select { |k| 2*k if k > 1 }
=> [4, 6]
>> [1, 2, 3].map_detect { |k| 2*k if k > 1 }
=> 4
延迟迭代(lazy_map,lazy_select,...)。例如:
>> 1.upto(1e100).lazy_map { |x| 2 *x }.first(5)
=> [2, 4, 6, 8, 10]
答案 4 :(得分:0)
计算满足一种或另一种情况的物品数量:
items.count do |item|
next true unless first_test?(item)
next true unless second_test?(item)
false
end
count
表示您不必执行i = 0
和i += 1
。
next
意味着您可以完成该块的迭代并仍然提供答案,而不是一直闲逛直到结束。
(如果你愿意,你可以用单行! second_test?(item)
替换块的最后两行,但这会让它看起来更麻烦)
答案 5 :(得分:0)
探索字符串的布尔成员方法:
"".methods.sort.grep(/\?/)
探索特定于字符串的方法:
"".methods.sort - [].methods