How to best count nested objects in Groovy - grails

I have a Groovy class which looks a lot like this:
class A {
B[] requests = []
}
In code, I have an array of A and I'd like to know how many B are contained within it. What's the most groovyish way to make that calculation? I know how to do it in Java, but it looks far uglier than I suspect Groovy would like it to be. Here's what I've worked out so far:
list.each{ a -> count += a.requests.size() }
Is there a better way?

When coding this, I'd invoke the KISS principle regarding maintenance and clarity. Not everything should use shiny features.
Your version is reasonably 'Groovy', though you may want to consider using the implicit variable it (see doc):
def count = 0
list.each{ count += it.requests.size() }

Use spread operator (*)
class A {
B[] requests = []
}
class B{
String name
}
assert [
new A(requests : [new B(name: 'John'), new B(name: 'Jim'),
new B(name: 'Alex')]),
new A(requests : [new B(name: 'Test'), new B(name: 'Alex')]),
new A(requests : [new B(name: 'John')])
]*.requests*.size() == [3, 2, 1]

Related

Building a map for parallel step from directory names [duplicate]

For example, the groovy File class has a nice iterator that will filter out just directories and not files:
void eachDir(Closure closure)
When I use eachDir, I have to use the verbose method of creating the collection first and appending to it:
def collection = []
dir1.eachDir { dir ->
collection << dir
}
Any way to get it back to the nice compact collect syntax?
I don't know of any "idiomatic" way of doing this, nice riddle! =D
You can try passing the eachDir, or any similar function, to a function that will collect its iterations:
def collectIterations(fn) {
def col = []
fn {
col << it
}
col
}
And now you can use it as:
def dir = new File('/path/to/some/dir')
def subDirs = collectIterations(dir.&eachDir)
def file = new File('/path/to/some/file')
def lines = collectIterations(file.&eachLine)
(that last example is equivalent to file.readLines())
And only for bonus points, you may define this function as a method in the Closure class:
Closure.metaClass.collectIterations = {->
def col = []
delegate.call {
col << it
}
col
}
def dir = new File('/path/to/some/dir')
def subDirs = dir.&eachDir.collectIterations()
def file = new File('/path/to/some/file')
def lines = file.&eachLine.collectIterations()
Update: On the other hand, you might also do:
def col = []
someDir.eachDir col.&add
Which I think is quite less convoluted, but it's not leveraging the collect method as you requested :)
Not for the specific example that you're talking about. File.eachDir is sort of a weird implementation IMO. It would have been nice if they implemented iterator() on File so that you could use the normal iterator methods on them rather than the custom built ones that just execute a closure.
The easiest way to get a clean one liner that does what you're looking for is to use listFiles instead combined with findAll:
dir1.listFiles().findAll { it.directory }
If you look at the implementation of eachDir, you'll see that it's doing this (and a whole lot more that you don't care about for this instance) under the covers.
For many similar situations, inject is the method that you'd be looking for to have a starting value that you change as you iterate through a collection:
def sum = [1, 2, 3, 4, 5].inject(0) { total, elem -> total + elem }
assert 15 == sum

Groovy - with closure with multiple references

I'm trying to parse a JSON data and assign it to a POJO in Grails.
I started with
obj.param=jsonRequest.jsonWrap.attrib.something.jsonParam
After some experimenting and refactoring, it looks like this now.
jsonRequest.jsonWrap.attrib.something.with {
obj.param1=jsonParam1
obj.param2=jsonParam2
//...
}
}
Now, can I avoid the repeated use of obj reference?
I'm imagining that your actual starting point is something like the following. On the JSON side:
import groovy.json.JsonSlurper
String jsonText = '''{
"jsonWrap":{
"attrib":{
"something":{
"jsonParam1": "value1",
"jsonParam2": "value2",
"jsonParam3": "value3",
"jsonParam4": "value4",
"jsonParam5": "value5"
}
}
}
}'''
def jsonRequest = new JsonSlurper().parseText(jsonText)
On the Groovy side:
class ObjectType {
def param1, param2, param3, param4, param5
}
def obj = new ObjectType()
Now, if I had any control over how either the JSON side or the Groovy side are defined then I would do my darnedest to ensure that the property names of the JSON "something" object are exactly the same as the property names in the Groovy "ObjectType" class. For example, like this:
class ObjectType {
def jsonParam1, jsonParam2, jsonParam3, jsonParam4, jsonParam5
}
Then, unmarshalling the "something" object into Groovy is as simple as this:
def obj = new ObjectType(jsonRequest.jsonWrap.attrib.something)
Only one reference to the JSON object. Only one reference to the Groovy object. And the former is used to instantiate the latter. And furthermore, notice that there is no need to reference the properties at all. That is, JSON objects from the slurper are instances of Map, so if the property names match up, you can use the default "Map constructor" syntax.
If, however, you do not control property naming in either set of objects, I would still recommend a different Map-based short-cut. First define a constant Map from one set of property names to the other, like so:
def map = [param1:"jsonParam1", param2:"jsonParam2", param3:"jsonParam3",
param4:"jsonParam4", param5:"jsonParam5"]
Then I would use something like this for the object unmarshalling:
def obj = new ObjectType().with { o ->
jsonRequest.jsonWrap.attrib.something.with { j ->
map.each { oParam, jParam -> o[oParam] = j[jParam] }
}
o
}
i don't think there is a trivial way to trick groovy into "use objectA, if getting is needed and objectB for setting". If obj above is a map or you can apply a map to this object, then you could produce a map in your with block and use this. If you have to have nested structures then more work is needed.
def jsonParam = new Expando([ p1: 'p1', p2: 'p2', p3: 'p3', ])
def obj = new Expando(
jsonParam.with{
[
param1: p1,
param3: p3,
] // `with` will return this map
})
assert obj.param1==jsonParam.p1
assert obj.param3==jsonParam.p3
I use expandos for simple code.

how do I build a tree hierarchy from a list in groovy using recursive closure?

I defined the recursive domain class in grails:
class Work {
String code
String title
String description
static hasMany = [subWorks:Work]
static mappedBy = [subWorks: 'parentWork']
Work getRootWork(){
if(parentWork) return parentWork.getRootWork()
else return this
}
boolean isLeafWork(){
return subWorks.isEmpty()
}
boolean isRootWork(){
return !parentWork
}
I have a list of Works, but the hierarchy structure is not built yet. The structure looks like:
def works = [new Work(code:'A', title:'TitleA'),
new Work(code:'B', title:'TitleB'),
new Work(code:'A.1', title:'Titile A.1'),
new Work(code:'B.1', title:'Title B.1'),
new Work(code:'B.2', title:'Title B.2'),
new Work(code:'B.3', title:'Title B.3'),
new Work(code:'B.2.2', title:'Title B.2.2'),
new Work(code:'B.2.3', title:'Title B.2.3'),
new Work(code:'A.1.1', title:'Title A.1.1'),
new Work(code:'A.1.2', title:'Title A.1.2'),]
What I need is to build the hierarchical relationship among these works, based on the code hinted. e.g. A.1 is the first child work of A; B.1.1 is the first child of B.1 work, whose parent is B work. I know that Groovy supports recursive closures to build this kind of hierarchical structure. How do I achieve my goal using Groovy recursive closure, such as the JN2515 Fibonacci number example, in Groovy official documentation?
Many thanks!
like this...?
def root = new Work(code:'*', title:'ROOT')
def build
build = { p, list ->
list.groupBy{it.code.split('\\.').first()}.each{ el, sublist ->
el = sublist[0]
el.parentWork = p
if(sublist.size()>1){
build(el, sublist[1..-1] )
}
}
}
build(root, works.sort{it.code.length()})
if I'm not in error even in this anonim form may work
def root = new Work(code:'*', title:'ROOT')
{ p, list ->
list.groupBy{it.code.split('\\.').first()}.each{ el, sublist ->
el = sublist[0]
el.parentWork = p
if(sublist.size()>1){
call(el, sublist[1..-1] )
}
}
}(root, works.sort{it.code.length()})
I am a bit rusty with Grails, but i seem to remember that it managed mapped collections in an intelligent way, such that if you do: work1.parentWork = work2 then work1 in work2.subWorks will verify. If that's the case, all you need to do is set the parentWork for every work, and you don't need to do any complicated computation for this: the parent work of X.Y.Z will be X.Y, and the parent work of X will be none:
def works = [new Work(code:'A', title:'TitleA'),
new Work(code:'B', title:'TitleB'),
new Work(code:'A.1', title:'Titile A.1'),
new Work(code:'B.1', title:'Title B.1'),
new Work(code:'A.1.1', title:'Title A.1.1')]
def worksByCode = works.collectEntries { [it.code, it] }
works.each {
if (it.code.contains('.')) {
def parentCode = it.code[0..it.code.lastIndexOf('.') - 1]
it.parentWork = worksByCode[parentCode]
}
}

Can I append a closure to another in Groovy?

I have two very similar methods in Grails, something like "calculate statistics by os" and "calculate statistics by browser" - effectively both prepare some things, then run a similar query on the DB, then do things with the results. The only part where the methods differ is the query they run in the middle of my method -
def summary = c.list {
eq('browser', Browser.get(1)) // OR eq('os', OS.get(1))
between('date', dates.start, dates.end)
}
It occurred to me that the ideal way to refactor it would be to pass in the first line of the closure as a method parameter. Like
doStats (Closure query) {
...
def summary = c.list {
query
between('date', dates.start, dates.end)
}
}
I tried this but "query" gets ignored. I tried query() instead but then the query clause is executed where defined, so this doesn't work either. I suppose I could just pass the whole closure as a parameter but that seems wrong - the query might also get more complicated in future.
Anyone have any better ideas?
I found leftShift operator useful for composing closure from two separate ones. What you can do is:
Closure a = { /*...*/ }
Closure b = { /*...*/ }
Closure c = a << b
Take a look at this example:
def criteria = {
projection Projections.distinct(Projections.property('id'))
and {
eq 'owner.id', userDetails.id
if (filter.groupId) {
eq 'group.id', filter.groupId
}
}
}
List<Long> ids = Contact.createCriteria().list(criteria << {
maxResults filter.max
firstResult filter.offset
})
Integer totalCount = Contact.createCriteria().count(criteria)
What you can see here is that I'm creating a criteria for listing ant counting GORM objects. Criterias for both cases are almost the same, but for listing purposes I also need to include limit and offset from command object.
You're using the criteria DSL which might be different than plain groovy closures.
To do what you're asking, you can use the method described here -
http://mrhaki.blogspot.com/2010/06/grails-goodness-refactoring-criteria.html
and put your query in to private method.
The more elegant solution for this is to use named queries in grails -
http://grails.org/doc/latest/ref/Domain%20Classes/namedQueries.html
Look at the
recentPublicationsWithBookInTitle {
// calls to other named queries…
recentPublications()
publicationsWithBookInTitle()
}
example -
Not sure about with the Grails Criteria builder, but with other builders, you can do something like:
doStats (Closure query) {
def summary = c.list {
query( it )
between('date', dates.start, dates.end)
}
}
And call this via:
def f = { criteria ->
criteria.eq( 'browser', Browser.get( 1 ) )
}
doStats( f )
If not, you're probably best looking at named queries like tomas says

Is there an analog in Scala for the Rails "returning" method?

In Rails, one could use:
returning Person.create do |p|
p.first_name = "Collin"
p.last_name = "VanDyck"
end
Avoiding having to do this:
person = Person.create
person.first_name = "Collin"
person.last_name = "VanDyck"
person
I think the former way is cleaner and less repetitive. I find myself creating this method in my Scala projects:
def returning[T](value: T)(fn: (T) => Unit) : T = {
fn(value)
value
}
I know that it is of somewhat limited utility due to the tendency of objects to be immutable, but for example working with Lift, using this method on Mapper classes works quite well.
Is there a Scala analog for "returning" that I'm not aware of? Or, is there a similar way to do this in Scala that's more idiomatic?
Your method looks fine, though I normally do this by adding a method for side-effects, which can include changing internal state (or also stuff like println):
class SideEffector[A](a: A) {
def effect(f: (A => Any)*) = { f.foreach(_(a)); a }
}
implicit def can_have_side_effects[A](a: A) = new SideEffector(a)
scala> Array(1,2,3).effect(_(2) = 5 , _(0) = -1)
res0: Array[Int] = Array(-1, 2, 5)
Edit: just in case it's not clear how this would be useful in the original example:
Person.create.effect(
_.first_name = "Collin",
_.last_name = "VanDyck"
)
Edit: changed the name of the method to "effect". I don't know why I didn't go that way before--side effect, not side effect for the naming.
Can't really improve much on what you've already written. As you quite correctly pointed out, idiomatic Scala tends to favour immutable objects, so this kind of thing is of limited use.
Plus, as a one-liner it's really not that painful to implement yourself if you need it!
def returning[T](value: T)(fn: T => Unit) : T = { fn(value); value }
I would do:
scala> case class Person(var first_name: String = "", var last_name: String = "")
defined class Person
scala> Person(first_name="Collin", last_name="VanDyck")
res1: Person = Person(Collin,VanDyck)
I don't understand why Vasil deleted his own answer, but I like it a lot (it was precisely what I was going to suggest):
val person = Person.create
locally { import person._
first_name = "Collin"
last_name = "VanDyck"
}
person
One of the features people have been asking for is the ability to auto-import something. If it were possible, then you could do this:
def returning[T](import value: T)(fn: => Unit) : T = { fn; value }
returning(Person.create) {
first_name = "Collin"
last_name = "VanDyck"
}
That is not possible at the moment, nor is it in Scala's roadmap. But some people do ask for something like that now and again.
It is possible to avoid repeating the variable name like so:
val person = Person.create
locally { import person._
first_name = "Collin"
last_name = "VanDyck"
}
Note that this only works for vals. Also, locally is a Predef method that helps to create blocks just to limit variable scope, without running afoul of Scala's semicolon inference. This keeps the import from getting in your way once you have finished initializing the person.
Another suggestion would be using the forward pipe operator from Scalaz.
val person = Person.create |> { p =>
p.firstName = "Collin"
p.lastName = "VanDyck"
p // or p.saveMe
}
The difference is that you would have to return the value yourself, if you want to assign it. If you do not need the return value (as in your initial example), things are easier:
Person.create |> { p =>
p.firstName = "Collin"
p.lastName = "VanDyck"
p.save
}
And there you go.
I was reluctant to really use it in my own code (even though I kind of favour this way of doing it – but it is only documented in scalaz and maybe hard to figure out for other people looking at the code), so I hope these examples do work.
You could of course define your own ‘forward and returning pipe’ using |>.
class ReturningPipe[A](value: A) {
import Scalaz._
def |>>[B](f: A => B):A = value.|>(a => { f(a); value})
}
implicit def returningPipe[A](value: A) = new ReturningPipe(value)

Resources