2012-02-24 16 views
28

Czy istnieje .collect z indeksem? Chcę zrobić coś takiego:.collect ze wskaźnikiem

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

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

(czyli chcę ustawić position do wartości, która będzie wskazywać kolejność na liście.)

+2

wygląda na to, że jest to cecha o http: //jira.codehaus.org/browse/GROOVY-2838 – dstarh

+0

odpowiedział rzeczywistym rozwiązaniem poniżej – dstarh

+0

Co nie miłość do mojego zbierania z indeksem :) – dstarh

Odpowiedz

11

eachWithIndex prawdopodobnie działać lepiej:

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

Korzystanie z collectX nie wydaje się konieczne, ponieważ modyfikuje się kolekcję i nie zwraca się jej do nowej kolekcji.

+9

, chyba że potrzebujesz go do zwrotu nowej kolekcji – dstarh

+1

@dstarh - Tak, ale pytanie brzmi: "Chcę ustawić pozycję na wartość", co sprawiłoby, że kolekcja wydawałaaby się niepotrzebna. –

+4

zgodził się, zbieranie prawdopodobnie nie jest konieczne w tym przypadku. Czy byłby to łańcuch innych połączeń, które byłyby inne. Nadal jednak chciałbym zobaczyć kolekcję z indeksem – dstarh

6

Należy to zrobić dokładnie to, co chcesz

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]] 
1

dstarh Jak powiedział, chyba że szukasz nieniszczących metodą, która zwraca nową mapę ze swoimi indeksów zaludnionych, Rob Hruska jest odpowiedzią jest to, czego szukam.

dstarh Odpowiedź zawiera nieniszczącą wersję collectWithIndex, ale obsługuje także rzeczywisty zbiór wyników.

Zazwyczaj najlepiej oddelegować takie ciężkie podnoszenie do obiektu odbierającego, aby grać ładnie z polimorficznymi implementacjami collect, tj. W przypadku, gdy określona klasa implementuje collect inaczej (niż tylko umieszczanie wyników w tablicy), mając collectWithIndex Delegowanie do niego zapewni jednolite zachowanie. Oto jak kod będzie wyglądał:

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

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

Patrz this gist na przykład zarówno eachWithIndex i collectWithIndex.

Ponadto, podobnie jak komentarze do stanu zapytania, istnieją dwie kwestie Jira otwarty dla funkcji mamy described- GROOVY-2383 & GROOVY-3797

13

Lekko groovier wersji collectWithIndex:

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

lub nawet

List.metaClass.collectWithIndex = {body-> 
    [delegate, 0..<delegate.size()].transpose().collect(body) 
} 
3

Bez dodawania jakichkolwiek metod rozszerzających można to zrobić w całkiem prosty sposób lub dalszy sposób:

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

Byłoby z pewnością użyteczne, aby ta metoda istniała jednak automatycznie.

60

Od Groovy 2.4.0 istnieje metoda withIndex(), która zostaje dodana do java.lang.Iterable.

Więc w funkcjonalny sposób (nie efekt uboczny, niezmienne), wygląda

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"]] 
} 
+4

Głosuj, że to powinna być najlepsza odpowiedź. – solvingJ

Powiązane problemy