raccourci pour créer une Carte à partir d'une Liste de groovy?

j'aimerais un peu de sorthand pour ceci:

Map rowToMap(row) {
    def rowMap = [:];
    row.columns.each{ rowMap[it.name] = it.val }
    return rowMap;
}

étant donné la façon dont le GDK est, je m'attends à pouvoir faire quelque chose comme:

Map rowToMap(row) {
    row.columns.collectMap{ [it.name,it.val] }
}

mais je n'ai rien vu dans les docs... ai-je raté quelque chose? ou suis-je tout simplement trop paresseux?

96
demandé sur danb 2008-08-20 22:37:51
la source

8 ответов

j'ai récemment découvert le besoin de faire exactement cela: convertir une liste en une carte. Cette question a été postée avant Groovy version 1.7.9 sorti, de sorte que la méthode collectEntries n'existait pas encore. Il fonctionne exactement comme la collectMap méthode qui a été proposé :

Map rowToMap(row) {
    row.columns.collectEntries{[it.name, it.val]}
}

si pour une raison quelconque vous êtes coincé avec une version Groovy plus ancienne, la méthode inject peut également être utilisé (comme proposé ici ). Il s'agit d'une version légèrement modifiée qui ne prend qu'une seule expression à l'intérieur de la fermeture (juste pour sauver des caractères!):

Map rowToMap(row) {
    row.columns.inject([:]) {map, col -> map << [(col.name): col.val]}
}

l'opérateur + peut également être utilisé à la place du << .

106
répondu epidemian 2017-05-23 14:46:46
la source

Check out "injecter". La programmation fonctionnelle réelle wonks l'appellent "fold".

columns.inject([:]) { memo, entry ->
    memo[entry.name] = entry.val
    return memo
}

et, pendant que vous y êtes, vous voulez probablement définir des méthodes en tant que Catégories au lieu de droit sur le metaClass. De cette façon, vous pouvez le définir une fois pour toutes les Collections:

class PropertyMapCategory {
    static Map mapProperty(Collection c, String keyParam, String valParam) {
        return c.inject([:]) { memo, entry ->
            memo[entry[keyParam]] = entry[valParam]
            return memo
        }
    }
}

exemple d'usage:

use(PropertyMapCategory) {
    println columns.mapProperty('name', 'val')
}
28
répondu Robert Fischer 2008-10-13 22:48:46
la source

la méthode groupBy n'était-elle pas disponible lorsque cette question a été posée?

13
répondu Amir Raminfar 2015-06-12 18:00:51
la source

aussi, si vous utilisez google collections ( http://code.google.com/p/google-collections / ), vous pouvez faire quelque chose comme ceci:

  map = Maps.uniqueIndex(list, Functions.identity());
5
répondu ogrodnek 2008-08-21 02:32:57
la source

ok... J'ai joué avec ce un peu plus et je pense que c'est une super méthode...

def collectMap = {Closure callback->
    def map = [:]
    delegate.each {
        def r = callback.call(it)
        map[r[0]] = r[1]
    }
    return map
}
ExpandoMetaClass.enableGlobally()
Collection.metaClass.collectMap = collectMap
Map.metaClass.collectMap = collectMap

maintenant n'importe quelle sous-classe de carte ou de Collection ont cette méthode...

ici, je l'utilise pour inverser la clé/valeur dans une Carte

[1:2, 3:4].collectMap{[it.value, it.key]} == [2:1, 4:3]

et ici, je l'utilise pour créer une carte à partir d'une liste

[1,2].collectMap{[it,it]} == [1:1, 2:2]

maintenant je viens de pop dans une classe qui est appelé comme mon application commence et cette méthode est disponible tout au long de mon code.

EDIT:

pour ajouter la méthode à tous les tableaux...

Object[].metaClass.collectMap = collectMap
5
répondu danb 2008-08-21 22:21:18
la source

si vous avez besoin d'une simple paire de clés, alors la méthode collectEntries devrait suffire. Par exemple

def names = ['Foo', 'Bar']
def firstAlphabetVsName = names.collectEntries {[it.charAt(0), it]} // [F:Foo, B:Bar]

mais si vous voulez une structure similaire à un Multimap, dans lequel il y a plusieurs valeurs par clé, alors vous voulez utiliser la groupBy méthode

def names = ['Foo', 'Bar', 'Fooey']
def firstAlphabetVsNames = names.groupBy { it.charAt(0) } // [F:[Foo, Fooey], B:[Bar]]
4
répondu Nerrve 2017-03-09 11:06:40
la source

Je ne trouve rien de construit... mais en utilisant L'ExpandoMetaClass je peux faire ceci:

ArrayList.metaClass.collectMap = {Closure callback->
    def map = [:]
    delegate.each {
        def r = callback.call(it)
        map[r[0]] = r[1]
    }
    return map
}

ajoute la méthode collectMap à tous les tableaux... Je ne sais pas pourquoi l'ajouter à la liste ou à la Collection n'a pas fonctionné.. Je suppose que c'est une autre question... mais maintenant, je peux le faire...

assert ["foo":"oof", "42":"24", "bar":"rab"] ==
            ["foo", "42", "bar"].collectMap { return [it, it.reverse()] }

de la liste à la carte calculée avec une fermeture... exactement ce que je cherchais.

Edit: la raison pour laquelle je n'ai pas pu ajouter la méthode à la liste des interfaces et la collecte était parce que je n'ai pas fait cela:

List.metaClass.enableGlobally()

après cet appel de méthode, vous pouvez ajouter des méthodes aux interfaces.. ce qui dans ce cas signifie que ma méthode collectMap fonctionnera sur des plages comme celle-ci:

(0..2).collectMap{[it, it*2]}

qui donne la carte: [0:0, 1:2, 2:4]

1
répondu danb 2008-08-21 02:43:50
la source

Qu'en est-il de quelque chose comme ça?

// setup
class Pair { 
    String k; 
    String v; 
    public Pair(def k, def v) { this.k = k ; this.v = v; }
}
def list = [ new Pair('a', 'b'), new Pair('c', 'd') ]

// the idea
def map = [:]
list.each{ it -> map.putAt(it.k, it.v) }

// verify
println map['c']
0
répondu Michael Easter 2008-09-29 21:41:19
la source

Autres questions sur