ruby – 在数组上使用累加器映射
|
我正在寻找为Enumerable创建一个同时映射和注入的方法.例如,将其称为map_with_accumulator,
[1,2,3,4].map_with_accumulator(:+) # => [1,6,10] 或者用于字符串 ['a','b','c','d'].map_with_accumulator {|acc,el| acc + '_' + el}
# => ['a','a_b','a_b_c','a_b_c_d']
我找不到解决方案.我想我可以用reduce来做.我正在沿着这样的道路前进: arr.reduce([]) {|acc,e| ..... }
初始值是一个空数组,但我无法正确. 编辑:请参阅下面的J?rg答案以获得正确的解决方案.另一种(有点粗略)的方法我在阅读他的答案之后意识到使用instance_eval,它将给定块的上下文更改为执行它的对象的上下文.因此self设置为引用数组而不是调用上下文(这意味着它不再是闭包!)并且数组调用注入和移位.令人费解,不必要的简洁,令人困惑的阅读,但它教会了我一些新的东西. ['a','d'].instance_eval do
inject([shift]) {|acc,el| acc << acc.last+el}
end
#=> ['a','ab','abc','abcd']
解决方法
此操作称为
scan or prefix_sum,但遗憾的是,Ruby核心库或标准库中没有实现.
但是,你的直觉是正确的:你可以使用Enumerable#inject实现它. (实际上,Enumerable#inject是通用的,每次迭代操作都可以使用inject实现!) module Enumerable
def scan(initial)
inject([initial]) {|acc,el| acc << yield(acc.last,el) }
end
end
[1,4].scan(0,&:+)
# => [0,1,10]
%w[a b c d].scan('') {|acc,el| acc + '_' + el }
# => ["","_a","_a_b","_a_b_c","_a_b_c_d"]
理想情况下,行为应该与inject的4次重载相匹配(在这种情况下它会给你指定的结果),但不幸的是,在Ruby中实现了这些重载,没有对VM内部的特权访问(特别是在发送网站)是后部的主要痛苦. 它是这样的: module Enumerable
# Trying to match the signature of `inject` without access to the VM internals
# is a PITA :-(
def scan(initial=(initial_not_given = true; first),meth=nil)
raise ArgumentError,'You can pass either a block or a method,not both.' if block_given? && meth
return enum_for(__method__) if initial_not_given && !meth && !block_given?
return enum_for(__method__,initial) unless initial.is_a?(Symbol) || meth || block_given?
meth,initial,initial_not_given = initial,first,true unless initial_not_given || meth || block_given?
raise ArgumentError,"Method #{meth.inspect} is not a Symbol." unless meth.is_a?(Symbol) || block_given?
this = if initial_not_given then drop(1) else self end
return this.inject([initial]) {|acc,el| acc << acc.last.__send__(meth,el) } unless block_given?
this.inject([initial]) {|acc,4].scan(:+)
# => [1,10]
%w[a b c d].scan {|acc,el| acc + '_' + el }
# => ["a","a_b","a_b_c","a_b_c_d"]
正如您所看到的,注入本身的实现相当优雅,丑陋仅仅是因为在没有超载的情况下实现了语言的重载. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |
