working with groovy collections

Post on 17-Jan-2017

251 Views

Category:

Software

2 Downloads

Preview:

Click to see full reader

TRANSCRIPT

Ted VinkeFirst8 September 2015

COLLECTIONSgroovyCollections.each { “working with $it” }

Overview• Java Collections Basics

• Iterable & Collection• Groovy Makes Things Easy

• List, Set, Range, Map• GDK’s Iterable & Collection

• Some examples• collate, collect, collectEntries, every and any, find,

findResults, groupBy, inject, removeAll, sum• References

JAVA COLLECTIONS BASICSWhere it all starts

Java Collections

Iterable interface• iterator

Iterator interface• hasNext• next• remove

Collection interface• add• addAll• clear• contains(Object)• containsAll(Collection)• isEmpty• iterator• remove• removeAll• retainAll• size• toArray

GROOVY MAKES THINGS EASY

Groovy Makes Things Easy• Creating a collection

• list = new ArrayList() vs list = []• map = new HashMap() vs map = [:]

• Working with elements• Addition e.g. list.add(3) vs list << 3• Retrieval e.g. map.get('color') vs map.color

• Overloading• list1.addAll(list2) vs list1 + list2

Listdef list = ['a', 'b']list << 'c'assert list.size() == 3assert list.get(0) == 'a'assert list instanceof java.util.List

def emptyList = []assert emptyList.size() == 0

List is an ordered collection of elements

Setdef list = ['a', 'b']list << 'c'list << 'c'assert list.size() == 4

def set = list as Setassert set.size() == 3assert set instanceof java.util.Set

Set is a collection with no duplicates

Rangedef range = 5..8assert range.size() == 4assert range[2] == 7assert range instanceof java.util.List

range = 'a'..'d'assert range.size() == 4assert range[2] == 'c'assert range.from == 'a'assert range.to == 'd'

Range is an extension of List

Mapdef map = [name: 'Ted', age: 34]map.color = 'blue'assert map.size() == 3assert map['name'] == 'Ted'assert map instanceof java.util.Map

def emptyMap = [:]assert emptyMap.size() == 0

Map maps keys to values – e.g. a dictionary.

No duplicate keys.

Tip: def“The keyword def is

great for examples, but not always so much for

real API design.”

IT’S NOT ONLYSYNTACTIC SUGAR

addAll, addAll, addAll, asBoolean, asImmutable, asSynchronized, asType, collect, collect, collect, collectNested, each, eachWithIndex, find, find, findAll, findAll, findResult,findResult, flatten, getAt, getIndices, grep, grep, inject, inject, intersect, isCase, leftShift, minus, plus, plus, plus, removeAll, removeAll, removeElement, retainAll, retainAll,split, toListString, toListString, toSet, unique, unique, unique, unique, unique, unique Groovy’s Collection

any, asCollection, asList, collate, collate, collate, collate, collectEntries, collectEntries, collectEntries, collectEntries, collectMany, collectMany, collectNested,collectNested, combinations, combinations, contains, containsAll, count, count, countBy, disjoint, drop, dropRight, dropWhile, each, eachCombination, eachPermutation,eachWithIndex, every, findResults, first, flatten, flatten, getAt, groupBy, groupBy, groupBy, head, indexed, indexed, init, intersect, join, last, max, max, max, min, min, min, minus,minus, multiply, permutations, permutations, plus, plus, size, sort, sort, sort, sort, sort, sum, sum, sum, sum, tail, take, takeRight, takeWhile, toList, toSet, toSorted, toSorted,toSorted, toSpreadMap, toUnique, toUnique, toUnique, withIndex, withIndex

Groovy’s Iterable

SOME EXAMPLES

collatedef names = ["Lassy", "Buttercup", "Carmella", "Moo-moo", "Cinnamon"]

// collate into batches of 3def collated = names.collate 3assert collated == [['Lassy', 'Buttercup', 'Carmella'], ['Moo-moo', 'Cinnamon']]

// and passing a step of 1collated = names.collate 3, 1assert collated == [['Lassy', 'Buttercup', 'Carmella'], ['Buttercup', 'Carmella', 'Moo-moo'], ['Carmella', 'Moo-moo', 'Cinnamon'], ['Moo-moo', 'Cinnamon'], ['Cinnamon']]

Remember closures?

def adder = { a, b -> print a+b }assert adder(1, 2) == 3assert adder("m", "e") == "me"

Closures are used a lot!• e.g. basic looping

• dogs.each { it.bark() }• names.each { name ->

println “Hello $name”}

• or whatever the methods’ Javadoc says

collectdef animals = []animals << new Animal(name: "Buttercup", age: 2)animals << new Animal(name: "Carmella", age: 5)animals << new Animal(name: "Cinnamon", age: 2)

// collect on Listdef names = animals.collect { it.name }assert names == ["Buttercup", "Carmella", "Cinnamon"] // names is java.util.ArrayList

// collect as a different type e.g. a Set, keeping only unique valuesassert animals.collect(new HashSet()) { it.age }.toString() == "[2, 5]"

collectEntriesdef john = new Farmer(name: "John")def dick = new Farmer(name: "Dick")

def animals = []animals << new Animal(name: "Buttercup", farmer: john)animals << new Animal(name: "Carmella", farmer: dick)animals << new Animal(name: "Cinnamon", farmer: dick)

// collect farmer name by animal namedef results = animals.collectEntries { animal -> [animal.name, animal.farmer.name]}assert results == ['Buttercup':'John', 'Carmella':'Dick', 'Cinnamon':'Dick']

every and anydef animals = []animals << new Animal(name: "Buttercup", age: 2)animals << new Animal(name: "Carmella", age: 5)animals << new Animal(name: "Cinnamon", age: 2)

// check if all animals are youngboolean allAreYoung = animals.every { it.age < 3 } assert !allAreYoung // Carmella is, with age 5, not young

// check if atleast one of them is youngboolean atleastOneIsYoung = animals.any { it.age < 3 }assert atleastOneIsYoung // Buttercup and Cinnamon are both young enough

finddef animals = []animals << new Animal(name: "Buttercup", age: 2)animals << new Animal(name: "Carmella", age: 5)animals << new Animal(name: "Cinnamon", age: 2)

// find first matching animal Animal foundAnimal = animals.find { it.age == 2 }assert foundAnimal.name == "Buttercup"

// find all matching animalsList foundAnimals = animals.findAll { it.name.startsWith "C" } assert foundAnimals.toString() == "[Carmella, Cinnamon]"

findResultsdef animals = []animals << new Animal(name: "Buttercup", age: 2)animals << new Animal(name: "Carmella", age: 5)animals << new Animal(name: "Cinnamon", age: 2)

// find all non-null resultsdef greetings = animals.findResults { it.age < 4 ? "Hello $it.name!" : null} assert greetings == ['Hello Buttercup!', 'Hello Cinnamon!']

groupBydef animals = []animals << new Animal(name: "Buttercup", country: "NL", age: 2)animals << new Animal(name: "Carmella", country: "NL", age: 5)animals << new Animal(name: "Cinnamon", country: "BE", age: 2)

// single closureMap animalsByCountry = animals.groupBy { it.country }assert animalsByCountry["NL"].size() == 2 // Buttercup and Carmellaassert animalsByCountry.BE.size() == 1 // Cinnamon

// list of closuresMap animalsByCountryAndAge = animals.groupBy( [{ it.country }, { it.age }] ) assert animalsByCountryAndAge.toString() == "[NL:[2:[Buttercup], 5:[Carmella]], BE:[2:[Cinnamon]]]"

injectdef animals = []animals << new Animal(name: "Buttercup", price: 2, farmer: "john")animals << new Animal(name: "Carmella", price: 5, farmer: "dick")animals << new Animal(name: "Cinnamon", price: 2, farmer: "dick")

// iteration, passing 1st item to closure, injecting results back into closure with 2nd item, etcassert 1 * 2 * 3 * 4 == [1, 2, 3, 4].inject { current, val -> current * val }

// gather the total price of all animals, passing initial price of 0assert 9 == animals.inject(0) { totalPrice, animal -> totalPrice + animal.price }// or...assert 9 == animals.price.inject(0) { totalPrice, price -> totalPrice + price}

removeAlldef animals = []animals << new Animal(name: "Buttercup", age: 2)animals << new Animal(name: "Carmella", age: 5)animals << new Animal(name: "Cinnamon", age: 2)

// remove all animals younger than 3animals.removeAll { it.age < 3 }assert animals.size() == 1assert animals.first().name == "Carmella"

sumdef animals = []animals << new Animal(name: "Buttercup", price: 2, farmer: "john")animals << new Animal(name: "Carmella", price: 5, farmer: "dick")animals << new Animal(name: "Cinnamon", price: 2, farmer: "dick")

// gather the total price of all animalsassert 9 == animals.sum { it.price }assert 9 == animals.price.sum()

MAKING COMBINATIONS

Animals by farmer// groupingdef animalsByFarmer =

animals.groupBy { it.farmer }

assert "[john:[Buttercup], dick:[Carmella, Cinnamon]]" == animalsByFarmer.toString()

Total price per farmer// grouping, collecting and summingdef totalPriceByFarmer = animals .groupBy { it.farmer } .collectEntries { k, v -> [k, v.price.sum()] }assert ['john':2, 'dick':7] == totalPriceByFarmer

Tip: sort mutatesdef animalList = createAnimals([])assert animalList instanceof java.util.ArrayListassert animalList.name == ["Lassy", "Buttercup", "Moo-moo"]

List sortedByAge = animalList.sort { it.age }assert animalList.name == ["Moo-moo", "Lassy", "Buttercup"]assert sortedByAge.name == ["Moo-moo", "Lassy", "Buttercup"]assert animalList.is(sortedByAge) // is() is same as == in plain Java

def animalSet = createAnimals([] as Set)assert animalSet instanceof java.util.HashSet

List sortedByName = animalSet.sort { it.name }assert sortedByName.name == ["Buttercup", "Lassy", "Moo-moo"]assert animalSet != sortedByNameassert !animalSet.is(sortedByName)

List againAnimalList = createAnimals([])// pass false as the 1st parameter to indicate NOT to mutate original ListList againSortedByAge = againAnimalList.sort(false) { it.age }assert againAnimalList.name == ["Lassy", "Buttercup", "Moo-moo"]assert againSortedByAge.name == ["Moo-moo", "Lassy", "Buttercup"]

def createAnimals = { c -> c << new Animal(name: "Lassy", age: 2) c << new Animal(name: "Buttercup", age: 3) c << new Animal(name: "Moo-moo", age: 1) c}

References• Oracle Java™ Tutorials: Collections Trailhttps://docs.oracle.com/javase/tutorial/collections/index.html

• The Groovy Dev Kit: Working with Collectionshttp://groovy-lang.org/groovy-dev-kit.html#_working_with_collections

• Groovy Closureshttp://groovy-lang.org/closures.html

top related