How to write a conditional collect in groovy?
Imagine I have this structure:
class Foo {
String bar
}
Now imagine I have several instance of Foo
whose bar
value is baz_1
, baz_2
, and zab_3
.
I want to write a collect statement that only collects the bar
values which contain the text baz
. I cannot get it to work, but it would look something like this:
def barsOfAllFoos = Foo.getAll().bar
assert barsOfAllFoos == [ 'baz_1', 'baz_2', 'zab_3' ]
def barsWithBaz = barsOfAllFoos.collect{ if( it.contains( "baz" ) { it } ) } // What is the correct syntax for this?
assert barsWithBaz == [ 'baz_1', 'baz_2' ]
Solution 1:
You need findAll
:
barsOfAllFoos.findAll { it.contains 'baz' }
Solution 2:
If you want to both filter and transform there's lots of ways to do this. After 1.8.1 I'd go with #findResults
and a closure that returns null for the elements I want to skip.
def frob(final it) { "frobbed $it" }
final barsWithBaz = barsOfAllFoos.findResults {
it.contains('baz')? frob(it) : null
}
In earlier versions you can use #findAll
and #collect
final barsWithBaz = barsOfAllFoos
. findAll { it.contains('baz') }
. collect { frob(it) }
Or #sum
final barsWithBaz = barsOfAllFoos.sum([]) {
it.contains('baz')? [frob(it)] : []
}
Or #inject
final barsWithBaz = barsOfAllFoos.inject([]) {
l, it -> it.contains('baz')? l << frob(it) : l
}
Solution 3:
Using findResults
did not work for me... If you want to collect a transformed version of the values matching the condition (for instance a regex search of many lines) you can use collect
followed by find
or findAll
as follows.
def html = """
<p>this is some example data</p>
<script type='text/javascript'>
form.action = 'http://www.example.com/'
// ...
</script>
"""
println("Getting url from html...")
// Extract the url needed to upload the form
def url = html.split("\n").collect{line->
def m = line =~/.*form\.action = '(.+)'.*/
if (m.matches()) {
println "Match found!"
return m[0][1]
}
}.find()
println "url = '${url}'"
This returns the part of the line matching the given pattern.
Getting url from html...
Match found!
url = 'http://www.example.com/'