10

I have a domain class that is just a list of strings (youtubeLinks).

When saving these links I want to strip out the video ID and save it instead of the entire URL entered on the UI side.

This is what I'm trying (ignore that the regex is flawed)

youtubeLinks.each {
 def youtubeRegex = /v=(.*)/
 def matcher = ( it =~ youtubeRegex )
 it = matcher[0][1]
}

When I save this, it saves the original value of "it". Is there a way to update this reference and have it save properly?

Thanks.

user577905
  • 173
  • 2
  • 8

2 Answers2

24

Groovy's each loop is merely an iterator, and as such it neither affects the collection on which it operates, nor returns a value of its own. It's basically equivalent to Java's "advanced for loop (for-each)," only with the convenience of dynamic typing and an implicit loop variable (it). While it can be modified, it's a futile enterprise, as you'd be simply changing a reference to the original value, not the value itself. See this question for more on that.

When you need to modify every element within a collection somehow, the idiomatic Groovy (Grails) solution is to use the collect method. Collect transforms each element via the closure you provide, ultimately returning a new collection ( so, it doesn't actually "modify" anything).

Basically, you'll probably want to do something like this:

def links = '''http://www.youtube.com/watch?v=fl6s1x9j4QQ
http://www.youtube.com/watch?v=tCvMKcNJCAY
'''

assert (links =~ /watch\?v=(.*)/).collect{match -> match[1]} == ["fl6s1x9j4QQ", "tCvMKcNJCAY"]

..Though there are actually a number of ways one could go about such a task in Groovy.

Additionally, Ted Naleid's blog has some nice examples of Groovy pattern matching that you may find useful.

Edit Here are several ways in which you could abbreviate the solution you submitted:

youtubeLinks = youtubeLinks.collect{link -> (link =~ /\?v=(.*)$/)[0][1]}

or

youtubeLinks = youtubeLinks.collect{link -> link.replaceAll(/^.*\?v=/, "") }

or this (Though it's a little contrived)

youtubeLinks = youtubeLinks.join('\n').replaceAll(/.*\?v=/, '').split()
Community
  • 1
  • 1
Northover
  • 981
  • 8
  • 14
2

You were right, it ended up being like

youtubeLinks = youtubeLinks.collect {
    def youtubeRegex = /v=(.*)[&]/
    def matcher = ( it =~ youtubeRegex )
    return matcher[0][1]
}

Thanks, Northover.

user577905
  • 173
  • 2
  • 8
  • 1
    Glad I could help. I've added some additional working solutions to my answer, if you're interested in ways of consolidating the code. Cheers. – Northover Jan 17 '11 at 21:21