2011-01-03 14 views
12

Mam dwie listy w Groovy i muszę zsumować zawartość obu.Suma zawartości 2 list w Groovy

Na przykład

list1 = [1,1,1] 
list2 = [1,1,1] 

I Oczekuje się, że wyniki:

total = [2,2,2] 

I próbie Podsumowując z + operatora o metody .sum, ale mają konkatenacji list.

[1, 1, 1, 1, 1, 1] 

Jest wystarczająco groovy lub muszę zapętlić każdy element list?

+1

Możliwe powtórzenie tego pytania: http://stackoverflow.com/questions/4443557/overloading-operator-for-arrays-in-groovy – Northover

Odpowiedz

33

Groovy za List.transpose() działa jak zip w niektórych innych językach. Wypróbuj to:

list1 = [1,2,3] 
list2 = [4,5,6] 
assert [list1, list2].transpose()*.sum() == [5,7,9] 
+0

to najmilsza odpowiedź do tej pory (przepraszam pozostawiono na dzisiaj). Jaka jest gwiazda? –

+2

To jest [operator rozprzestrzeniania się] (http://docs.codehaus.org/display/GROOVY/Operators?showChildren=false#Operators-SpreadOperator%28.%29), skrót dla 'collect' nad listą. – ataylor

+0

Dzięki tej niesamowitej odpowiedzi przypomniałem sobie pytanie, które zadałem wcześniej: [Klarowność a zaciemnianie] (http://stackoverflow.com/questions/4433137/clarity-vs-obfuscation-writing-code) –

2

W językach programowania najbardziej funkcjonalnych, odbywa się to za pomocą map2 (SML) lub zipWith funkcję (Haskell), z na przykład:

let total = List.map2 (+) list1 list2;; 

Nie mogę znaleźć żadnego odpowiednika w porywające dokumentacji, ale jak widać, można łatwo określić zipWith (znajdujący się w http://cs.calstatela.edu/wiki/index.php/Courses/CS_537/Summer_2008/Chapter_4._Collective_Groovy_datatypes):

zipWith = {f, a, b -> 
result = [] 
0.upto(Math.min(a.size(), b.size())-1){index -> result << f(a[index], b[index])} 
result} 

assert zipWith({x, y -> x + y}, [1, 2, 3], [4, 5, 6, 7]) == [5, 7, 9] 
1

Prototype (framework JavaScript) ma method zip() że robi dokładnie to, czego potrzebują. Wiem, że to ci nie pomoże. Zabawne, spodziewałbym się, że Groovy będzie miał coś podobnego, ale nie mogłem znaleźć niczego w klasie Collection lub List.

Zresztą, tutaj jest niezbyt ładna realizacja zip():

List.metaClass.zip = { List other, Closure cl -> 
    List result = []; 
    Iterator left = delegate.iterator(); 
    Iterator right = other.iterator(); 
    while(left.hasNext()&& right.hasNext()){ 
     result.add(
      cl.call(left.next(), right.next()) 
     ); 
    } 
    result; 
} 

I to jest tutaj w akcji:

def list1 = [1, 1, 1] 
def list2 = [1, 1, 1] 

print (list1.zip(list2) {it1, it2 -> it1 + it2}) 

wyjściowa:

[2, 2, 2]


Oczywiście można też zrobić to w mniej typowy sposób, jeśli chcesz, aby rozwiązać swój problem dokładnie (i nie realizuje funkcji rodzajowe pocztowy/MAP):

List.metaClass.addValues = { List other -> 
    List result = []; 
    Iterator left = delegate.iterator(); 
    Iterator right = other.iterator(); 
    while(left.hasNext()&& right.hasNext()){ 
     result.add(
      left.next() + right.next() 
     ); 
    } 
    result; 
} 

def list1 = [1, 1, 1] 
def list2 = [1, 1, 1] 

print (list1.addValues(list2)) 
// Output again: [2, 2, 2] 
4

ja nie znam wbudowany rozwiązanie, ale tutaj jest obejście tego problemu za pomocą collect i poll() metody Java Queue „s:

def list1 = [1, 2, 3] 
def list2 = [4, 5, 6] as Queue 

assert [5, 7, 9] == list1.collect { it + list2.poll() } 
+1

To jest oryginalne (+1) –

0

Jeśli znajdziesz.* Suma() rozwiązanie powyżej odrobinę mylące do odczytu (bardzo ładne chociaż) można też to zrobić:

l1=[1,2,3] 
l2=[4,5,6] 

println([l1,l2].transpose().collect{it[0]+it[1]}) 

Oczywiście to pozwala na bardziej skomplikowanych obliczeń niż tylko zsumowanie.