How to write a conditional collect in groovy?

Groovy

Groovy Problem Overview


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

Groovy Solutions


Solution 1 - Groovy

You need findAll:

barsOfAllFoos.findAll { it.contains 'baz' }

Solution 2 - Groovy

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 - Groovy

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/'

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionubiquibaconView Question on Stackoverflow
Solution 1 - Groovytim_yatesView Answer on Stackoverflow
Solution 2 - GroovyJustin PiperView Answer on Stackoverflow
Solution 3 - GroovyfrmdstryrView Answer on Stackoverflow