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"] 正如您所看到的,注入本身的实现相当优雅,丑陋仅仅是因为在没有超载的情况下实现了语言的重载. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |