Karten in Groovy

1. Übersicht

Groovy erweitert die Map- API in Java um Methoden für Vorgänge wie Filtern, Suchen und Sortieren . Es bietet auch eine Vielzahl von Kurzformen zum Erstellen und Bearbeiten von Karten.

In diesem Artikel werden wir uns die Groovy-Arbeitsweise mit Karten ansehen.

2. Groovy Map erstellen s

Wir können die Kartenliteral-Syntax [k: v] zum Erstellen von Karten verwenden. Grundsätzlich können wir eine Karte instanziieren und Einträge in einer Zeile definieren.

Eine leere Karte kann erstellt werden mit:

def emptyMap = [:]

Ebenso kann eine Karte mit Werten instanziiert werden mit:

def map = [name: "Jerry", age: 42, city: "New York"]

Beachten Sie, dass die Schlüssel nicht in Anführungszeichen gesetzt sind.

Und standardmäßig erstellt Groovy eine Instanz von java.util.LinkedHashMap . Wir können dieses Standardverhalten überschreiben, indem wir den Operator as verwenden .

3. Elemente hinzufügen

Beginnen wir mit der Definition einer Karte:

def map = [name:"Jerry"]

Wir können der Karte einen Schlüssel hinzufügen:

map["age"] = 42

Eine andere, eher Javascript-ähnliche Methode ist die Verwendung der Eigenschaftsnotation (der Punktoperator):

map.city = "New York"

Mit anderen Worten, Groovy unterstützt den Zugriff auf Schlüssel-Wert-Paare auf Bean-ähnliche Weise.

Wir können auch Variablen anstelle von Literalen als Schlüssel verwenden, während wir der Karte neue Elemente hinzufügen:

def hobbyLiteral = "hobby" def hobbyMap = [(hobbyLiteral): "Singing"] map.putAll(hobbyMap) assertTrue(hobbyMap.hobby == "Singing") assertTrue(hobbyMap[hobbyLiteral] == "Singing")

Zuerst müssen wir eine neue Variable erstellen, in der das Schlüsselhobby gespeichert ist. Dann verwenden wir diese in Klammern gesetzte Variable mit der Map-Literal-Syntax, um eine weitere Map zu erstellen.

4. Elemente abrufen

Die Literal-Syntax oder die Eigenschaftsnotation können verwendet werden, um Elemente aus einer Karte abzurufen.

Für eine Karte definiert als:

def map = [name:"Jerry", age: 42, city: "New York", hobby:"Singing"]

Wir können den Wert erhalten , um den Schlüssel entsprechenden Namen :

assertTrue(map["name"] == "Jerry")

oder

assertTrue(map.name == "Jerry")

5. Elemente entfernen

Mit der Methode remove () können wir jeden Eintrag basierend auf einem Schlüssel aus einer Karte entfernen . Aber manchmal müssen wir mehrere Einträge aus einer Karte entfernen. Dies kann mit der minus () -Methode erfolgen.

Die minus () -Methode akzeptiert eine Map . Und gibt eine neue Karte zurück, nachdem alle Einträge der angegebenen Karte aus der zugrunde liegenden Karte entfernt wurden:

def map = [1:20, a:30, 2:42, 4:34, ba:67, 6:39, 7:49] def minusMap = map.minus([2:42, 4:34]); assertTrue(minusMap == [1:20, a:30, ba:67, 6:39, 7:49])

Als nächstes können wir auch Einträge basierend auf einer Bedingung entfernen. Dies kann mit der Methode removeAll () erreicht werden:

minusMap.removeAll{it -> it.key instanceof String} assertTrue(minusMap == [1:20, 6:39, 7:49])

Um umgekehrt alle Einträge beizubehalten, die eine Bedingung erfüllen, können wir die Methode keepAll () verwenden:

minusMap.retainAll{it -> it.value % 2 == 0} assertTrue(minusMap == [1:20])

6. Durch Einträge iterieren

Wir können Einträge mit den Methoden each () und eachWithIndex () durchlaufen .

Die each () -Methode stellt implizite Parameter wie Eintrag , Schlüssel und Wert bereit , die dem aktuellen Eintrag entsprechen .

Die eachWithIndex () -Methode bietet neben Entry auch einen Index . Beide Methoden akzeptieren einen Abschluss als Argument.

Im nächsten Beispiel durchlaufen wir jeden Eintrag. Der an die each () -Methode übergebene Closure ruft das Schlüssel-Wert-Paar aus dem impliziten Parametereintrag ab und gibt es aus:

map.each{entry -> println "$entry.key: $entry.value"}

Als Nächstes verwenden wir die eachWithIndex () -Methode, um den aktuellen Index zusammen mit anderen Werten zu drucken:

map.eachWithIndex{entry, i -> println "$i $entry.key: $entry.value"}

Es ist auch möglich, den Schlüssel , den Wert und den Index separat anzugeben:

map.eachWithIndex{key, value, i -> println "$i $key: $value"}

7. Filtern

Wir können die Methoden find (), findAll () und grep () verwenden, um Karteneinträge basierend auf Schlüsseln und Werten zu filtern und zu suchen.

Beginnen wir mit der Definition einer Map, auf der diese Methoden ausgeführt werden sollen:

def map = [name:"Jerry", age: 42, city: "New York", hobby:"Singing"]

Zuerst betrachten wir die find () -Methode, die einen Abschluss akzeptiert und den ersten Eintrag zurückgibt, der der Abschlussbedingung entspricht :

assertTrue(map.find{it.value == "New York"}.key == "city")

Similarly, findAll also accepts a Closure but returns a Map with all the key-value pairs that satisfy the condition in the Closure:

assertTrue(map.findAll{it.value == "New York"} == [city : "New York"])

If we'd prefer to use a List, though, we can use grep instead of findAll:

map.grep{it.value == "New York"}.each{it -> assertTrue(it.key == "city" && it.value == "New York")}

We first used grep to find entries which have the value as New York. Then, to demonstrate the return type is List, we iterate through the result of grep(). And for each Entry in the list which is available in the implicit parameter, we check if its the expected result.

Next, to find out if all the items in a map satisfy a condition we can use every which returns a boolean.

Let's check if all values in the map are of type String:

assertTrue(map.every{it -> it.value instanceof String} == false)

Similarly, we can use any to determine if any items in the map match a condition:

assertTrue(map.any{it -> it.value instanceof String} == true)

8. Transforming and Collecting

At times we may want to transform the entries in a map into new values. Using the collect() and collectEntries() methods it's possible to transform and collect entries into a Collection or Map respectively.

Let's look at some examples.

Given a map of employee ids and employees:

def map = [ 1: [name:"Jerry", age: 42, city: "New York"], 2: [name:"Long", age: 25, city: "New York"], 3: [name:"Dustin", age: 29, city: "New York"], 4: [name:"Dustin", age: 34, city: "New York"]]

We can collect the names of all employees into a list using collect():

def names = map.collect{entry -> entry.value.name} assertTrue(names == ["Jerry", "Long", "Dustin", "Dustin"])

Next, if we're interested in a unique set of names, we can specify the collection by passing a Collection object:

def uniqueNames = map.collect([] as HashSet){entry -> entry.value.name} assertTrue(uniqueNames == ["Jerry", "Long", "Dustin"] as Set)

If we want to change the employee names in the map from lowercase to uppercase, we can use collectEntries. This method returns a map of transformed values:

def idNames = map.collectEntries{key, value -> [key, value.name]} assertTrue(idNames == [1:"Jerry", 2:"Long", 3:"Dustin", 4:"Dustin"])

Lastly, it's also possible to use collect methods in conjunction with the find and findAll methods to transform the filtered results:

def below30Names = map.findAll{it.value.age  value.name} assertTrue(below30Names == ["Long", "Dustin"])

Here, we first find all employees between ages 20-30 and collect them into a map.

9. Grouping

Sometimes we may want to group some items of a map into submaps based on a condition.

The groupBy() method returns a map of maps. And each map contains key-value pairs which evaluate to the same result for the given condition:

def map = [1:20, 2: 40, 3: 11, 4: 93] def subMap = map.groupBy{it.value % 2} assertTrue(subMap == [0:[1:20, 2:40], 1:[3:11, 4:93]])

Another way of creating submaps is by using subMap(). It is different in groupBy() in the sense that it only allows for grouping based on the keys:

def keySubMap = map.subMap([1,2]) assertTrue(keySubMap == [1:20, 2:40])

In this case, the entries for keys 1 and 2 are returned in the new map, and all the other entries are discarded.

10. Sorting

Usually, when sorting, we may want to sort the entries in a map based on key or value or both. Groovy provides a sort() method which can be used for this purpose.

Given a map:

def map = [ab:20, a: 40, cb: 11, ba: 93]

If sorting needs to be done on key, use the no-args sort() method which is based on natural ordering:

def naturallyOrderedMap = map.sort() assertTrue([a:40, ab:20, ba:93, cb:11] == naturallyOrderedMap)

Oder verwenden Sie die Sortiermethode (Comparator) , um eine Vergleichslogik bereitzustellen:

def compSortedMap = map.sort({k1, k2 -> k1  k2} as Comparator) assertTrue([a:40, ab:20, ba:93, cb:11] == compSortedMap)

Als nächstes entweder zu sortieren auf Schlüssel oder Werte oder beide, können wir eine Lieferung Closure Zustand sort () :

def cloSortedMap = map.sort({it1, it2 -> it1.value  it1.value}) assertTrue([cb:11, ab:20, a:40, ba:93] == cloSortedMap)

11. Schlussfolgerung

Wir haben uns zunächst angesehen, wie wir Karten in Groovy erstellen können . Als Nächstes haben wir uns verschiedene Möglichkeiten angesehen, wie Elemente zu einer Karte hinzugefügt, abgerufen und daraus entfernt werden können.

Später haben wir die Methoden zur Ausführung allgemeiner Operationen behandelt, die in Groovy sofort verfügbar sind. Dazu gehörten Filtern, Suchen, Transformieren und Sortieren.

Wie immer finden Sie die im Artikel behandelten Beispiele auf GitHub.