raccourci pour créer une carte à partir d’une liste dans groovy?

Je voudrais un coup de main pour cela:

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

Compte tenu de la manière dont le GDK fonctionne, je pense pouvoir faire quelque chose comme:

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

mais je n’ai rien vu dans les docs … Est-ce qu’il me manque quelque chose? ou suis-je trop paresseux?

Je suis récemment tombé sur le besoin de faire exactement cela: convertir une liste en une carte. Cette question a été postée avant la sortie de Groovy version 1.7.9, donc la méthode collectEnsortinges n’existait pas encore. Il fonctionne exactement comme la méthode collectMap proposée :

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

Si pour une raison quelconque vous êtes coincé avec une ancienne version de Groovy, la méthode d’ inject peut également être utilisée (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 << .

Découvrez “injecter”. Les vrais vrais programmeurs de la functional programming l’appellent “fold”.

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

Et, pendant que vous y êtes, vous souhaiterez probablement définir des méthodes en tant que catégories plutôt que sur la méta-classe. De cette façon, vous pouvez le définir une fois pour toutes les collections:

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

Exemple d’utilisation:

 use(PropertyMapCategory) { println columns.mapProperty('name', 'val') } 

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

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

  map = Maps.uniqueIndex(list, Functions.identity()); 

ok … j’ai joué avec un peu plus et je pense que c’est une méthode plutôt cool …

 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 toute sous-classe de Map ou Collection possède 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 placer cette classe dans une classe appelée au démarrage de mon application et cette méthode est disponible dans tout mon code.

MODIFIER:

append la méthode à tous les tableaux …

 Object[].metaClass.collectMap = collectMap 

Si ce dont vous avez besoin est une paire clé-valeur simple, alors la méthode collectEnsortinges devrait suffire. Par exemple

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

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

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

Je ne trouve rien de intégré … mais en utilisant ExpandoMetaClass, je peux le faire:

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

Cela ajoute la méthode collectMap à tous les ArrayLists … Je ne sais pas pourquoi l’append à List ou Collection n’a pas fonctionné. Je suppose que c’est pour 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 ne pouvais pas append la méthode aux interfaces List et Collection était que je ne l’avais pas fait:

 List.metaClass.enableGlobally() 

après cet appel de méthode, vous pouvez append des méthodes aux interfaces.

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

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

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

 // setup class Pair { Ssortingng k; Ssortingng 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']