2016-10-08 29 views
9

inject'un her değerini almak istiyorum.Enjeksiyon döngüsünün her bir değeri nasıl alınır

Örneğin [1,2,3].inject(3){|sum, num| sum + num}, 9 değerini döndürür ve tüm döngü değerlerini almak istiyorum. [1,2,3].inject(3).map{|sum, num| sum + num}'u denedim, ancak çalışmadı.

Yazdığım kod budur, ancak bunun gereksiz olduğunu hissediyorum.

a = [1,2,3] 
result = [] 
a.inject(3) do |sum, num| 
    v = sum + num 
    result << v 
    v 
end 

p result 
# => [4, 6, 9] 

aynı anda inject ve map kullanmak için bir yolu var mı?

+1

Ne [(veya 'scan') önek toplamı] (https://wikipedia.org/wiki/Prefix_sum#Scan_higher_order_function) denir arayan ve' fold' açısından [uygulama vardır ] (http://stackoverflow.com/q/2243812/2988) umduğumuz gibi önemsiz değildir. Ne yazık ki, 'scan' Ruby çekirdek kütüphanelerinin veya standart kütüphanelerin bir parçası değildir. –

cevap

5

mükemmel burada uyuyor, ama bu olay için daha genel bir yaklaşım gösterecektir: Bir o ne isterse toplamak olabilir (akümülatör olarak hash kullanarak)

[1,2,3].inject(map: [], sum: 3) do |acc, num| 
    acc[:map] << (acc[:sum] += num) 
    acc 
end 
#⇒ => {:map => [4, 6, 9], :sum => 9} 

O yolu. Sidenote: önceki sonraki her tekrarında bir nesnenin yeni bir örneğini oluşturmaz, çünkü daha iyi yerine inject burada Enumerable#each_with_object kullanımı:

[1,2,3].each_with_object(map: [], sum: 3) do |num, acc| 
    acc[:map] << (acc[:sum] += num) 
end 
+0

'100.times {p 'bu harika!' } ' –

1

iyi ben

def partial_sums(arr, start = 0) 
    sum = 0 
    arr.each_with_object([]) do |elem, result| 
    sum = elem + (result.empty? ? start : sum) 
    result << sum 
    end 
end 

partial_sums([1,2,3], 3) 
1

Bir sýralayýcý kullanabilirsiniz düşünebildiğim: Bir yöntemde güzel bu paketleyebilirim

Açıkçası
enum = Enumerator.new do |y| 
    [1, 2, 3].inject (3) do |sum, n| 
    y << sum + n 
    sum + n 
    end 
end 

enum.take([1,2,3].size) #=> [4, 6, 9] 

ama yapmak için bunu bırakacağım . Ayrıca, teşebbüsünüzde yanlış bir şey olduğunu düşünmeyin, güzel çalışır. adanmış Eumerator kullanma

1
def doit(arr, initial_value) 
    arr.each_with_object([initial_value]) { |e,a| a << e+a[-1] }.drop 1 
end 

arr = [1,2,3] 
initial_value = 4 

doit(arr, initial_value) 
    #=> [5, 7, 10] 

Bu genelleştirilmiş olmasının çok uygundur.

def gen_doit(arr, initial_value, op) 
    arr.each_with_object([initial_value]) { |e,a| a << a[-1].send(op,e) }.drop 1 
end 

gen_doit(arr, initial_value, :+) #=> [5,7,10] 
gen_doit(arr, initial_value, '-') #=> [3, 1, -2] 
gen_doit(arr, initial_value, :*) #=> [4, 8, 24] 
gen_doit(arr, initial_value, '/') #=> [4, 2, 0] 
gen_doit(arr, initial_value, :**) #=> [4, 16, 4096] 
gen_doit(arr, initial_value, '%') #=> [0, 0, 0] 
+1

Ayrıca, bir codeblock parametresi de kullanılabilir:' def gen_doit (arr, initial_value); arr.each_with_object ([initial_value]) {| e, a | bir << verim (e, bir [-1])} .drop 1; end '⇒' gen_doit ([1,2,3], 4) do | e, a | e + a '(veya 'gen_doit ([1,2,3], 4, &: +)') ⇒ '# => [5, 7, 10]'. – mudasobwa