Суммируйте содержимое списка 2 в Groovy

У меня есть два списка в Groovy, и мне нужно суммировать содержимое обоих.

Например:

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

Я ожидал такого результата:

total = [2,2,2]

Я пытаюсь суммировать с помощью оператора + или метода .sum, но у меня есть конкатенация списков.

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

Это достаточно Groovy или мне нужно зациклить каждый элемент списков?


person Arturo Herrero    schedule 03.01.2011    source источник
comment
Возможное повторение этого вопроса: stackoverflow.com/ вопросы/4443557/   -  person Northover    schedule 03.01.2011


Ответы (5)


List.transpose() от Groovy работает как zip на некоторых других языках. Попробуй это:

list1 = [1,2,3]
list2 = [4,5,6]
assert [list1, list2].transpose()*.sum() == [5,7,9]
person ataylor    schedule 03.01.2011
comment
пока что это лучший ответ (извините, на сегодня не осталось голосов). Что за звезда? - person Sean Patrick Floyd; 03.01.2011
comment
Это оператор расширения, сокращение для collect над списком. - person ataylor; 03.01.2011
comment
С этим удивительным ответом я вспомнил вопрос, который задавал ранее: Clarity vs Obfuscation - person Arturo Herrero; 04.01.2011

Я не знаю встроенного решения, но вот обходной путь с использованием collect и метода Java Queue poll():

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

assert [5, 7, 9] == list1.collect { it + list2.poll() }
person Christoph Metzendorf    schedule 03.01.2011

В большинстве языков функционального программирования это делается с помощью функции map2 (ocaml) или zipWith (haskell), например:

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

Я не нашел эквивалента в документации по groovy, но, по-видимому, вы можете легко определить zipWith (находится по адресу 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]
person tonio    schedule 03.01.2011

Prototype (инфраструктура JavaScript) имеет метод zip(), который делает именно то, что вам нужно. Хотя это тебе не поможет, я знаю. Забавно, я ожидал, что в Groovy будет что-то подобное, но я не смог найти ничего ни в Collection или List.

Во всяком случае, вот не слишком красивая реализация 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;
}

И вот он в действии:

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

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

Выход:

[2, 2, 2]


Конечно, вы также можете сделать это менее общим способом, если хотите решить именно свою проблему (а не реализовывать общую функцию zip/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]
person Sean Patrick Floyd    schedule 03.01.2011

Если вы обнаружите, что решение .*sum() выше немного сбивает с толку (хотя очень приятно), вы также можете сделать это:

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

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

Конечно, это позволяет выполнять более сложные расчеты, чем просто суммирование.

person Dino Fancellu    schedule 01.02.2013