собрать с индексом - PullRequest
       18

собрать с индексом

36 голосов
/ 24 февраля 2012

Есть ли .collect с индексом? Я хочу сделать что-то вроде этого:

def myList = [
    [position: 0, name: 'Bob'],
    [position: 0, name: 'John'],
    [position: 0, name: 'Alex'],
]

myList.collect { index ->
    it.position = index
}

(т.е. я хочу установить для position значение, которое будет указывать порядок в списке)

Ответы [ 6 ]

81 голосов
/ 05 августа 2015

Начиная с Groovy 2.4.0, существует метод withIndex(), который добавляется к java.lang.Iterable.

Таким образом, функциональным образом (без побочных эффектов, неизменяемый)выглядит как

def myList = [
  [position: 0, name: 'Bob'],
  [position: 0, name: 'John'],
  [position: 0, name: 'Alex'],
]

def result = myList.withIndex().collect { element, index ->
  [position: index, name: element["name"]] 
}
13 голосов
/ 25 октября 2012

Немного классная версия collectWithIndex:

List.metaClass.collectWithIndex = {body->
    def i=0
    delegate.collect { body(it, i++) }
}

или даже

List.metaClass.collectWithIndex = {body->
    [delegate, 0..<delegate.size()].transpose().collect(body)
}
12 голосов
/ 24 февраля 2012

eachWithIndex, вероятно, будет работать лучше:

myList.eachWithIndex { it, index ->
    it.position = index
}

Использование collectX на самом деле не кажется необходимым, поскольку вы просто изменяете коллекцию и не возвращаете ее отдельные части в новую коллекцию.

7 голосов
/ 24 февраля 2012

Это должно делать именно то, что вы хотите

List.metaClass.collectWithIndex = {cls ->
    def i = 0;
    def arr = [];
    delegate.each{ obj ->
        arr << cls(obj,i++)
    }
    return arr
}



def myCol = [
    [position: 0, name: 'Bob'],
    [position: 0, name: 'John'],
    [position: 0, name: 'Alex'],
]


def myCol2 = myCol.collectWithIndex{x,t -> 
    x.position = t
    return x
}

println myCol2

=> [[position:0, name:Bob], [position:1, name:John], [position:2, name:Alex]]
4 голосов
/ 29 октября 2014

Без добавления каких-либо методов расширения вы можете сделать это довольно простым способом:

def myList = [1, 2, 3]
def index = 0
def myOtherList = myList.collect {
  index++
}

Конечно, было бы полезно, чтобы этот метод существовал автоматически.

1 голос
/ 15 марта 2012

Как сказал dstarh , если вы не ищете неразрушающий метод, который возвращает новую карту с заполненными индексами, Роб Хруска ответит то, что выищу.

dstarh ответ предоставляет вам неразрушающую версию collectWithIndex, но обрабатывает фактический набор результатов тоже.

Я обычно нахожу еголучше всего делегировать такой тяжелый груз получающему объекту, чтобы хорошо играть с полиморфными реализациями collect, т. е. в случае, если конкретный класс реализует collect иначе (чем просто помещение результатов в массив), имея делегат collectWithIndexэто обеспечит равномерное поведение.Вот как будет выглядеть код:

@Category(List)
class Enumerator {
    def collectWithIndex(Closure closure) {
        def index = 0
        this.collect { closure.call(it, index++) }
    }
}

use(Enumerator) {
    ['foo', 'bar', 'boo', 'baz'].collectWithIndex { e, i ->
        [index: i, element: e]
    }
}

Обратитесь к этой сущности за примером для eachWithIndex и collectWithIndex.

Также как и комментариик состоянию вашего вопроса, есть две проблемы Jira, открытые для функции, которую мы описали - GROOVY-2383 & GROOVY-3797

...