2010-04-21 23 views
30

Mam dwie (lub więcej) tablice z 12 liczbami całkowitymi w każdej (odpowiada wartości dla każdego miesiąca). Wszystko czego chcę, to dodać je do siebie, dzięki czemu mam jedną tablicę z sumowanymi wartościami dla każdego miesiąca. Poniżej znajduje się przykład z trzech wartości: [1,2,3] i [4,5,6] => [5,7,9]ruby: suma odpowiadających członków dwóch lub więcej tablic

Najlepszym może wymyślić był następujący:

[[1,2,3],[4,5,6]].transpose.map{|arr| arr.inject{|sum, element| sum+element}} #=> [5,7,9] 

Czy jest lepszy sposób to zrobić? Po prostu wydaje się, że tak podstawową rzeczą jest chęć zrobienia.

Odpowiedz

41

Oto transpose wersja Anurag zasugerował:

[[1,2,3], [4,5,6]].transpose.map {|x| x.reduce(:+)} 

ta będzie współpracować z dowolną liczbą tablic składowych. reduce i inject są synonimami, ale reduce wydaje mi się bardziej wyraźnie komunikować intencje Kodeksu tu ...

+1

... lub w szynach: a.transpose.map {| x | x.sum} – jjnevis

+5

@jjnevis: cóż, jeśli gramy w golfa, to co powiesz na 'a.transpose.map (&: sum)' – rampion

+0

@rampion: To z pewnością dość lakoniczne - czy możesz wyjaśnić (&: sum) bit ? Dzięki – jjnevis

6

oto moja próba code-golfa to rzecz:

// ruby 1.9 syntax, too bad they didn't add a sum() function afaik 
[1,2,3].zip([4,5,6]).map {|a| a.inject(:+)} # [5,7,9] 

zip powraca [1,4], [2,5], [3,6] i map sumy każdy sub-array.

+0

Nice. Jak by to działało z trzema lub więcej tablicami - powtarzam iterację nad nieznaną liczbą tablic, więc transpozycja działa dobrze, ponieważ mogę po prostu wepchnąć je do pustej tablicy i przetransponować to. Uwielbiam składnię ": +" dla wstrzykiwania (choć nie tak dobra jak metoda sum(), jak mówisz, szyny dodaje ją, ale) - nie widzisz tego wcześniej, dzięki. – jjnevis

+0

zip jest metodą Array i akceptuje dowolną liczbę tablic jako parametry. Ale nie wiem, jak byś je zdał, gdyby były tworzone dynamicznie. "transpozycja" wydaje się lepszym wyborem. Ruby zazwyczaj obejmuje wiele powszechnie używanych funkcji, ale gdzie brak, Rails przychodzi na ratunek! – Anurag

+2

Powiedz, że 'aoa' jest naszą tablicą tablic i chcesz obliczyć' [aoa [0] [0] + aoa [1] [0] + ... + aoa [-1] [0], aoa [0 ] [1] + aoa [1] [1] + ... + aoa [-1] [1], ..., aoa [0] [- 1] + aoa [1] [- 1] + .. . + aoa [-1] [- 1]] 'możesz wtedy zrobić' first, * rest = * aoa; first.zip (* rest) .map {| a | a.inject (&: +)} ' – rampion

5
[[1,2,3],[4,5,6]].transpose.map{|a| a.sum} #=> [5,7,9] 
+2

Pamiętaj, że to nie działa w prostym Ruby. Może tak jest w Railsach, [zgodnie z sugestią jjnevisa] (http://stackoverflow.com/questions/2682411/ruby-sum-correspond--embers-of-two-arrays#comment2702699_2682983). – FriendFX

7

Dla jaśniejszego składni (nie najszybszy), można skorzystać z Vector:

require 'matrix' 
Vector[1,2,3] + Vector[4,5,6] 
=> Vector[5, 7, 9] 

dla wielu wektorów, można zrobić:

arr = [ Vector[1,2,3], Vector[4,5,6], Vector[7,8,9] ] 
arr.inject(&:+) 
=> Vector[12, 15, 18] 

Jeśli chcesz załadować tablice do wektorów i suma:

arrays = [ [1,2,3], [4,5,6], [7,8,9] ] 
arrays.map { |a| Vector[*a] }.inject(:+) 
=> Vector[12, 15, 18] 
+1

To zdecydowanie najczystsze z punktu widzenia zrozumienia. –

+1

Aby przekonwertować tablicę na wektor, możesz także użyć 'Vector.elements ([1, 2, 3])', oprócz 'Vector [* a]'. –

1

@FriendFX, masz rację pod względem odpowiedzi @ user2061694. W moim przypadku działało to tylko w środowisku Rails. można je uruchomić w czystym Ruby jeśli dokonać następujących zmian ...

W IRB

[[0, 0, 0], [2, 2, 1], [1,3,4]].transpose.map {|a| a.inject(:+)} 
=> [3, 5, 5] 


[[1,2,3],[4,5,6]].transpose.map {|a| a.inject(:+)} 
=> [5, 7, 9] 
0

To może nie być najlepszą odpowiedź, ale to działa.

array_one = [1,2,3] 
array_two = [4,5,6] 
x = 0 
array_three = [] 
while x < array_one.length 
    array_three[x] = array_one[x] + array_two[x] 
    x += 1 
end 

=>[5,7,9] 

To może być więcej linii kodu niż inne odpowiedzi, ale jest to odpowiedź mimo

+0

Podoba mi się ten po prostu dlatego, że jest bardzo jasne, co się dzieje, ale można go trochę wyczyścić za pomocą "array_one.each_index do | x | " – jjnevis

+0

to nie jest bardzo idiomatyczny Ruby. Użycie pętli' while' jest * bardzo * rzadkie –

4

Pokornie czuć, że pozostałe odpowiedzi widzę są tak skomplikowane, że będą one mylące dla recenzentów kodu. Trzeba dodać komentarz objaśniający, który po prostu zwiększa ilość potrzebnego tekstu.

Jak walka to zamiast:

a_arr = [1,2,3] 
b_arr = [4,5,6] 
(0..2).map{ |i| a_arr[i] + b_arr[i] } 

Nieco inne rozwiązanie: (tak, że nie jesteś ciężko kodowania "2")

a_arr = [1,2,3] 
b_arr = [4,5,6] 
c_arr = [] 
a_arr.each_index { |i| c_arr[i] = a_arr[i] + b_arr[i] } 

Wreszcie matematycznie rzecz biorąc, jest to ta sama pytanie jak to:

How do I perform vector addition in Ruby?

1

Dla:

a = [1,2,3] 
b = [4,5,6] 

Mogłeś zip a następnie użyć reduce:

p a.zip(b).map{|v| v.reduce(:+) } 
#=> [5, 7, 9] 

Lub, jeśli jesteś pewien, że tablica a i b zawsze będzie jednakowej długości:

p a.map.with_index { |v, i| v + b[i] } 
#=> [5, 7, 9] 
+0

Dwa bardzo eleganckie rozwiązania, chociaż zaktualizowałem tytuł, aby dokładniej odzwierciedlać pytanie, a mianowicie, że jest to "dwa lub więcej "tablic, więc tablica lub tablice naprawdę." – jjnevis

4

Teraz może używać sum w 2.4

nums = [[1, 2, 3], [4, 5, 6]] 
nums.transpose.map(&:sum) #=> [5, 7, 9] 
+0

suma jest również zdefiniowana z szynami 4.2.7, https://apidock.com/rails/Enumerable/sum – Obromios

Powiązane problemy