Groovy collection api
- 4. notation, lists
def emptyList = []
assert [] instanceof ArrayList
def list = [1,2,3]
assert list[1..-1] == [2,3]
assert list[-3..-2] == [1,2]
assert list[2..1] == [3,2]
- 5. notation, maps
def emptyMap = [:]
assert [:] instanceof LinkedHashMap // predictable order
assert [a:1, b:2] == ['a':1, 'b':2]
method(a:1, b:2)
// illusion of named parameters
- 6. ranges are lists
assert (1..3) == [1,2,3]
assert (1..<3) == [1,2]
assert (1..3) instanceof IntRange // groovy.lang
assert (1..3) instanceof List
- 7. notation, list operators
assert
assert
assert
assert
[1,2] << 3 == [1,2,3]
// leftShift()
[1,2]+3 == [1,2,3]
// plus()
[1,2]+[3,4] == [1,2,3,4]
[1,2,3]-[3,4] == [1,2]
// minus()
- 10. each
[1,2,3].each { println it}
[1,2,3].each { item -> println item }
[1,2,3].eachWithIndex { item, i -> println "index ${i} contains ${item}" }
[1,2,3].reverseEach { println it }
- 12. collect (map)
assert [1,2,3].collect { it * it } == [1,4,9]
assert [1,[2,3],4].collectNested { it*it } == [1,[4,9],16]
assert [1,2,3].collectEntries { ['k' +it, it] } == [k1:1,k2:2,k3:3]
- 14. reducers
assert [1,2,3].max() == 3
assert [1,2,3].min() == 1
assert [1,2,3].sum() == 6
assert [1,2,3].max{ -it } == 1
assert [1,2,3].max{ a,b-> b<=>a } == 1
- 16. reducers, inject
assert [1,2,3].inject(0)
{ acc, val -> acc+val } == 6
assert [1,2,3].inject("0") { acc, val -> acc+val } == "0123"
assert [1,2,3].inject([]) { acc, val -> acc+val } == [1,2,3]
assert [a:1,b:2].inject(0) { acc, key, val -> acc+val } == 3
- 20. set operations
assert [1,2]+3 == [1,2,3]
assert [1,2]+[3,4] == [1,2,3,4]
assert [1,2].plus([3,4]) == [1,2,3,4]
assert [1,2,3]-3 == [1,2]
assert [1,2,3]-[2,3] == [1]
assert [1,2,3].minus([2,3]) == [1]
assert [1,2,3].intersect([3,4]) == [3]
assert [1,2,3].disjoint([4,5]) == true
assert [1,2,3].subsequences() == [[3], [1, 2, 3], [1], [2], [2, 3], [1, 3], [1, 2]] as Set
assert [1,2,3].permutations() == [[1, 2, 3], [2, 3, 1], [3, 2, 1], [3, 1, 2], [2, 1, 3], [1, 3, 2]] as Set
assert [[1,2],[3,4]].combinations() == [[1, 3], [2, 3], [1, 4], [2, 4]]
- 21. Nested Collections
assert [1,[2,3],4].flatten() == [1,2,3,4]
assert [1,[2,3],4].collectNested { it+10 } == [11,[12,13],14]
assert [['a','b'], [1,2]].transpose() == [['a',1],['b',2]]
- 22. functional style
assert [1,2,3].head() == 1
assert [1,2,3].tail() == [2,3]
assert [1,2,3].first() == 1
assert [1,2,3].last() == 3
assert [1,2,3].take(2) == [1,2]
assert [1,2,3].drop(2) == [3]
assert [1,2,3].split { it<3 } == [[1,2],[3]]
- 23. list as stack
NOTE: mutates!
def list = [1,2,3]
list.push(4)
assert list == [1,2,3,4]
assert list.pop() == 4
assert list == [1,2,3]
- 26. map withDefault
def newMap = [:].withDefault { [] }
[a:1,b:2,c:2].each { key, val ->
newMap[val] << key
}
assert newMap == [1:['a'], 2:['b','c']]
- 27. mutability
•
•
•
•
all methods return new collections/objects
•
a few exceptions exist, such as push/pop and sort(boolean mutate)
objects and collections are generally mutable
use asImmutable(), asSynchronized() for multithreading
or better: use gpars (included in groovy jdk)
•
(that’s a different talk - coming up on groovy meetup!)
- 32. real-world example
params.findAll { key, val ->
// filtrer kun diagnose-parametre
key.startsWith(paramPrefix+"diagnoser")
}.groupBy { key, val ->
// grupper på rader
key.substring(0,"diagnoser[0]".size())
}.findAll { rowKey, rowMap ->
// Fjern tomme rader
rowMap.any { key, val -> val && val != "null" }
}.inject([:]) { acc, key, val ->
// ungroup rader (tilbake til en map med parametre)
acc + val
}.collectEntries { key, val ->
// hent sykdomskode.id
if (key.endsWith('.sykdomskode') && val) {
[key+'.id', Sykdomskode.findByNr(val)?.id ?: ""]
} else {
[key, val]
}
}.sort {
it.key
}
- 36. sample data
@EqualsAndHashCode @ToString class Person { def name, address, pets }
@EqualsAndHashCode @ToString class Address { def street, city }
enum Pet { CAT, DOG, BIRD, DUCK }
import static Pet.*
def persons = [
new Person(name:"Ole",
address:new Address(street:"Blindvn 1", city:"Oslo"),
pets:[BIRD, CAT]),
new Person(name:"Dole",
address:new Address(street:"Blindvn 2", city:"Oslo"),
pets:[DOG, CAT]),
new Person(name:"Doff",
address:new Address(street:"Strandvn 9", city:"Bergen"),
pets:[BIRD, DOG]),
]
assert persons.pets == [ [BIRD, CAT], [DOG, CAT], [BIRD, DOG]]
assert persons.pets.flatten().unique() == [BIRD, CAT, DOG]
assert persons.address.city.unique() == ["Oslo", "Bergen"]
- 37. real-world example
import org.ccil.cowan.tagsoup.Parser
@Grab(group='org.ccil.cowan.tagsoup', module='tagsoup', version='0.9.7')
def gdocHome = "http://groovy.codehaus.org/groovy-jdk/"
def gdocs = ["java/lang": ["Object[]","Object"],
"java/util": ["Collection", "List", "Map"]]
gdocs.inject([:]) { agg, key, val ->
// create map of [class:url]
agg + val.collectEntries { [it, gdocHome + key+"/"+it+".html" ] }
}.collectEntries { className, url ->
// parse urls
def html = new XmlParser(new Parser()).parse(url)
[className, html.body.table[1].tr[1..-1].collect {
it.td[1].code.b.a.text()
}]
}
- 38. • gå dypt i utvalgte kall, ex
•
•
•
•
groupBy
inject
findResult: find + transform
nested collections: collectNested
Editor's Notes
- merk strings og charsequence
- Bra for named parameters!
- Some say thats bad, wtf
- leftShift == putte inn i - operatoren
- Ta litt tid hero
- isNumber er en String operasjon (ikke en collection operasjon)
- Collections har ikke properties, så variant 2 representerer ikke noen tvetydigheter
- Trofast, første møtet
Returnerer ingenting (jo, umodifisert collection)
Bare en vanlig for-loop, en blindvei på veien mot funksjonell nirvana
Avhengig av side-effekter for å utføre noe.
- find burde kanskje hete findFirst
burde vært en alias for filter - det er det ikke
- Heter map i mange språk, men collect passer godt i en java-verden
map henviser jo til noe helt annet
Veldig nyttig: hvis man vil ha map: bruk collectEntries, returner en array [key, val]
tygg på navnet: godt navn
- Fra 30000 fot: bilde!!
- Reducers - noen kaller det foldLeft, silly :)
(alle disse tar også transformer/comparator for ikke-standard sammenligning)
- Dette er lett ;)
Burde hett reduce. foldLeft i mange språk. foldRight Mangler i groovy.
Ta litt tid: 1) initial value 2) to understand: closure returns next accumulator
- Bare mer komplisert. Hva gjør den nullen der? (indikerer at raden skal filtreres bort - ikke akkurat selvforklarende)
Jeg nevner dette for det ikke står i doken
- Her er de fleste collection-metoder (+ noen fler) definert resten er i StringGroovyMethods