2009-09-25 16 views
22

में संचयी सरणी राशि एक सरणी के संचयी योग की गणना करने का सबसे धीमा, सबसे रूबी-जैसा तरीका क्या है?रूबी

उदाहरण:

[1,2,3,4].cumulative_sum 

[1,3,6,10] 
+0

केवल 5.5 साल बाद इस प्रश्न पर वापस आ रहा है! – Peter

उत्तर

33
class Array 
    def cumulative_sum 
    sum = 0 
    self.map{|x| sum += x} 
    end 
end 
+0

या बस 'sum + = x', मुझे लगता है। – Peter

+0

हां, इसे अद्यतन किया गया: स्कैनर के संदर्भ के लिए पी – khelll

9

यहाँ वापस आना होगा एक ही रास्ता

a = [1, 2, 3, 4] 
a.inject([]) { |x, y| x + [(x.last || 0) + y] } 

अगर यह ठीक है कि इस सवाल का जवाब एक से अधिक बयान है, तो यह हो सकता है क्लीनर:

outp = a.inject([0]) { |x, y| x + [x.last + y] } 
outp.shift # To remove the first 0 
7
irb> a = (1..10).to_a 
#=> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] 
irb> a.inject([0]) { |(p,*ps),v| [v+p,p,*ps] }.reverse[1..-1] 
#=> [1, 3, 6, 10, 15, 21, 28, 36, 45, 55] 

हम भी हास्केल से लिख लेना चाहिए और scanr के एक गहरे लाल रंग का संस्करण बना सकते हैं।

irb> class Array 
    > def scanr(init) 
    >  self.inject([init]) { |ps,v| ps.unshift(yield(ps.first,v)) }.reverse 
    > end 
    > end 
#=> nil 
irb> a.scanr(0) { |p,v| p + v } 
=> [0, 1, 3, 6, 10, 15, 21, 28, 36, 45, 55] 
irb> a.scanr(0) { |p,v| p + v }[1..-1] 
=> [1, 3, 6, 10, 15, 21, 28, 36, 45, 55] 
irb> a.scanr(1) { |p,v| p * v } 
=> [1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880, 3628800] 
+0

+1, यह एक संचित इंजेक्शन है। ध्यान दें कि आप केवल वर्ग ऐरे के बजाय मॉड्यूल के लिए स्कैनर जोड़ सकते हैं। – tokland

1

एक और दृष्टिकोण (हालांकि मैं khell के पसंद करते हैं)

(1..10).inject([]) { |cs, i| cs << i + (cs.last || 0) } 

मैं अपने जवाब पोस्ट करने के बाद जवाब hrnt द्वारा पोस्ट की गई देखा। हालांकि दो दृष्टिकोण समान दिखते हैं, ऊपर समाधान अधिक कुशल है क्योंकि प्रत्येक इंजेक्शन चक्र में एक ही सरणी का उपयोग किया जाता है।

a,r = [1, 2, 3, 4],[] 
k = a.inject(r) { |x, y| x + [(x.last || 0) + y] } 
p r.object_id 
# 35742260 
p k.object_id 
# 35730450 

आप r और कश्मीर अलग हैं देखेंगे। यदि आप ऊपर दिए गए समाधान के लिए एक ही परीक्षण करते हैं:

a,r = [1, 2, 3, 4],[] 
k = a.inject(r) { |cs, i| cs << i + (cs.last || 0) } 
p r.object_id 
# 35717730 
p k.object_id 
# 35717730 

आर और के लिए ऑब्जेक्ट आईडी समान हैं।

+1

cs.last.to_i में भी संशोधित किया जा सकता है - कम नहीं, लेकिन शायद अधिक पठनीय? – TCSGrad

2

इसके अलावा आप scanl - सुविधा की आवश्यकता के बारे में पढ़ सकते हैं, लेकिन यह अभी तक रूबी में लागू नहीं है, जहां तक ​​मुझे पता है। यहाँ उदाहरण और नमूना स्रोत यह कोड हैं: http://billsix.blogspot.com/2008/11/functional-collection-patterns-in-ruby.html

युपीडी: ऊपर के लिंक मर चुका है, इसलिए बजाय मैं कहूँगा कि Wolfram मेथेमेटिका के FoldList[] मणि के एक भाग के रूप में "MLL" here कर सकते हैं की मेरी रूबी कार्यान्वयन जबकि Enumerable जा रहा ओपी के प्रयोजन के लिए सरल किया जा:

def fold_list array 
    start = 0 
    Enumerator.new do |e| 
    array.each do |i| 
     e << start += i 
    end 
    end 
end 

irb> fold_list([1,2,3]).to_a 
=> [1, 3, 6] 
+0

लिंक टूटा हुआ है (404)। – amoebe

+0

हाँ (इसके लिए बहुत से लिंक हैं लेकिन यह मर चुका है। मुझे उम्मीद है कि किसी को दर्पण मिल जाएगा। – Nakilon

1

एक और दृष्टिकोण के लिए यह उजागर, कि सरणी को संशोधित करता है यथा-स्थान

class Array 
    def cumulative_sum! 
    (1..size-1).each {|i| self[i] += self[i-1] } 
    self 
    end 
end 

भी सामान्यीकृत किया जा सकता:

def cumulate!(&block) 
    (1..size-1).each {|i| self[i] = yield self[i-1], self[i] } 
    self 
    end 

    >> (1..10).to_a.cumulate! {|previous, next| previous * next } 
    => [1, 2, 6, 24, 120, 720, 5040, 40320, 362880, 3628800] 
1

इस कोड

[1,2,3,4].inject([]){ |acc, value| acc << acc.last.to_i + value.to_i } 

=> [1, 3, 6, 10] 
0

प्रयास करें हास्केल समारोह हम चाहते हैं scanl, नहीं scanr है।

class Array 
    def scanl(init) 
    self.reduce([init]) { |a, e| a.push(yield(a.last, e)) } 
    end 
end 

[1,2,3,4].scanl(0) { |a, b| a + b }[1..-1] 
=> [1, 3, 6, 10]