Mapas em Groovy

Mapas em Groovy

1. Visão geral

Groovy estende a APIMap emJava paraprovide methods for operations such as filtering, searching and sorting. Ele também fornece umvariety of shorthand ways of creating and manipulating maps.

Neste artigo, veremos a maneira Groovy de trabalhar com mapas.

2. Criando GroovyMaps

We can use the map literal syntax [k:v] for creating maps. Basicamente, nos permite instanciar um mapa e definir entradas em uma linha.

Um mapa vazio pode ser criado usando:

def emptyMap = [:]

Da mesma forma, um mapa com valores pode ser instanciado usando:

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

Observe quethe keys aren’t surrounded by quotes.

And by default Groovy creates an instance of java.util.LinkedHashMap. Podemos substituir esse comportamento padrão usando o operadoras.

3. Adicionando itens

Vamos começar definindo um mapa:

def map = [name:"Jerry"]

Podemos adicionar uma chave ao mapa:

map["age"] = 42

Mas outra maneira mais semelhante ao Javascript é usar a notação de propriedade (o operador de ponto):

map.city = "New York"

Em outras palavras, o Groovy oferece suporte ao acesso de pares de valores-chave em um estilo de bean.

Também podemos usar variáveis ​​em vez de literais como chaves enquanto adicionamos novos itens ao mapa:

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

Primeiro, temos que criar uma nova variável que armazena a chavehobby.. Em seguida, usamos essa variável entre parênteses com a sintaxe literal do mapa para criar outro mapa.

4. Recuperando itens

A sintaxe literal ou a notação de propriedade pode ser usada para obter itens de um mapa.

Para um mapa definido como:

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

Podemos obter o valor correspondente à chavename:

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

or

assertTrue(map.name == "Jerry")

5. Removendo itens

Podemos remover qualquer entrada de um mapa com base em uma chave usando o métodoremove(). Mas,sometimes we may need to remove multiple entries from a map. This can be done using the minus() method.

O métodominus() aceita umMap. E retorna um novoMap após remover todas as entradas do mapa fornecido do mapa subjacente:

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

Em seguida, também podemos remover entradas com base em uma condição. Isso pode ser alcançado usando o métodoremoveAll():

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

Inversamente, para reter todas as entradas que satisfaçam uma condição, podemos usar o métodoretainAll():

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

6. Iterando Através de Entradas

Podemositerate through entries usando oeach() e métodoseachWithIndex().

O métodoeach() fornece parâmetros implícitos comoentry,key evalue que correspondem aoEntry atual.

O métodoeachWithIndex() também fornece um índice além deEntry. Ambos os métodos aceitamClosure como argumento.

No próximo exemplo, iteramos em cadaEntry. OClosure passado para o métodoeach() obtém o par de valores-chave da entrada de parâmetro implícito e o imprime:

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

Em seguida, usamos o métodoeachWithIndex() para imprimir o índice atual junto com outros valores:

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

Também é possível solicitar quekey,value,e índice sejam fornecidos separadamente:

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

7. Filtragem

Podemos usar os métodosfind(), findAll()egrep() para filtrar e pesquisar entradas de mapa com base em chaves e valores.

Vamos começar definindo um mapa para executar esses métodos em:

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

Primeiro, olhamos para o métodofind() que aceita umClosuree retorna o primeiroEntry que corresponde à condiçãoClosure:

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

Da mesma forma,findAll também aceitaClosure, mas retornaMap com todos os pares de valores-chave que satisfazem a condição emClosure:

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

Se preferirmos usar umList,, podemos usargrep em vez defindAll:

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

Primeiro usamos o grep para encontrar entradas com o valor de Nova York. Então, para demonstrar que o tipo de retorno éList, iteramos através do resultado degrep(). E para cadaEntry na lista que está disponível no parâmetro implícito, verificamos se é o resultado esperado .

A seguir, para descobrir se todos os itens em um mapa satisfazem uma condição, podemos usarevery, que retorna umboolean.

Vamos verificar se todos os valores no mapa são do tipoString:

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

Da mesma forma, podemos usarany para determinar se algum item no mapa corresponde a uma condição:

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

8. Transformando e coletando

Às vezes, podemos querer transformar as entradas em um mapa em novos valores. Using the collect() and collectEntries() methods it’s possible to transform and collect entries into a Collection or Map respectively.

Vejamos alguns exemplos.

Dado um mapa de IDs e funcionários:

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

Podemos coletar os nomes de todos os funcionários em uma lista usandocollect():

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

Em seguida, se estivermos interessados ​​em um conjunto único de nomes, podemos especificar a coleção passando um objetoCollection:

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

Se quisermos mudar os nomes dos funcionários no mapa de minúsculas para maiúsculas, podemos usarcollectEntries. Este método retorna um mapa de valores transformados:

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

Por último,it’s also possible to use collect methods in conjunction with the find and findAll methods para transformar os resultados filtrados:

def below30Names = map.findAll{it.value.age < 30}.collect{key, value -> value.name}
assertTrue(below30Names == ["Long", "Dustin"])

Aqui, primeiro encontramos todos os funcionários entre 20 e 30 anos e os reunimos em um mapa.

9. Agrupamento

Às vezes, podemos querer agrupar alguns itens de um mapa em submapas com base em uma condição.

O métodogroupBy() retorna um mapa de mapas. E cada mapa contém pares de valores-chave que avaliam o mesmo resultado para a condição fornecida:

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(). É diferente emgroupBy() no sentido de que só permite o agrupamento com base nas chaves:

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

Nesse caso, as entradas para as chaves 1 e 2 são retornadas no novo mapa e todas as outras entradas são descartadas.

10. Ordenação

Geralmente, ao classificar, podemos classificar as entradas em um mapa com base na chave, no valor ou em ambos. Groovy fornece um métodosort() que pode ser usado para essa finalidade.

Dado um mapa:

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

Se a classificação precisa ser feita na chave, use o método no-argssort(), que é baseado na ordem natural:

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

Ou use o métodosort(Comparator) para fornecer lógica de comparação:

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

A seguir,to sort on either key or values or both, we can supply a Closure condition to sort():

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

11. Conclusão

Começamos examinando como podemos criarMaps no Groovy. Em seguida, analisamos diferentes maneiras pelas quais os itens podem ser adicionados, recuperados e removidos de um mapa.

Mais tarde, abordamos os métodos para executar operações comuns que são fornecidas prontamente no Groovy. Eles incluíam filtragem, pesquisa, transformação e classificação.

Como sempre, os exemplos cobertos no artigo podem ser encontrados emGitHub.