Groovier way of manipulating the list - groovy

I have two list like this :
def a = [100,200,300]
def b = [30,60,90]
I want the Groovier way of manipulating the a like this :
1) First element of a should be changed to a[0]-2*b[0]
2)Second element of a should be changed to a[1]-4*b[1]
3)Third element of a should be changed to a[2]-8*b[2]
(provided that both a and b will be of same length of 3)
If the list changed to map like this, lets say:
def a1 = [100:30, 200:60, 300:90]
how one could do the same above operation in this case.
Thanks in advance.

For List, I'd go with:
def result = []
a.eachWithIndex{ item, index ->
result << item - ((2**index) * b[index])
}
For Map it's a bit easier, but still requires an external state:
int i = 1
def result = a.collect { k, v -> k - ((2**i++) * v) }
A pity, Groovy doesn't have an analog for zip, in this case - something like zipWithIndex or collectWithIndex.

Using collect
In response to Victor in the comments, you can do this using a collect
def a = [100,200,300]
def b = [30,60,90]
// Introduce a list `c` of the multiplier
def c = (1..a.size()).collect { 2**it }
// Transpose these lists together, and calculate
[a,b,c].transpose().collect { x, y, z ->
x - y * z
}
Using inject
You can also use inject, passing in a map of multiplier and result, then fetching the result out at the end:
def result = [a,b].transpose().inject( [ mult:2, result:[] ] ) { acc, vals ->
acc.result << vals.with { av, bv -> av - ( acc.mult * bv ) }
acc.mult *= 2
acc
}.result
And similarly, you can use inject for the map:
def result = a1.inject( [ mult:2, result:[] ] ) { acc, key, val ->
acc.result << key - ( acc.mult * val )
acc.mult *= 2
acc
}.result
Using inject has the advantage that you don't need external variables declared, but has the disadvantage of being harder to read the code (and as Victor points out in the comments, this makes static analysis of the code hard to impossible for IDEs and groovypp)

def a1 = [100:30, 200:60, 300:90]
a1.eachWithIndex{item,index ->
println item.key-((2**(index+1))*item.value)
i++
}

Related

Why am I getting a race condition in multi-threading scala?

I am trying to parallelise a p-norm calculation over an array.
To achieve that I try the following, I understand I can solve this differently but I am interested in understanding where the race condition is occurring,
val toSum = Array(0,1,2,3,4,5,6)
// Calculate the sum over a segment of an array
def sumSegment(a: Array[Int], p:Double, s: Int, t: Int): Int = {
val res = {for (i <- s until t) yield scala.math.pow(a(i), p)}.reduceLeft(_ + _)
res.toInt
}
// Calculate the p-norm over an Array a
def parallelpNorm(a: Array[Int], p: Double): Double = {
var acc = 0L
// The worker who should calculate the sum over a slice of an array
class sumSegmenter(s: Int, t: Int) extends Thread {
override def run() {
// Calculate the sum over the slice
val subsum = sumSegment(a, p, s, t)
// Add the sum of the slice to the accumulator in a synchronized fashion
val x = new AnyRef{}
x.synchronized {
acc = acc + subsum
}
}
}
val split = a.size / 2
val seg_one = new sumSegmenter(0, split)
val seg_two = new sumSegmenter(split, a.size)
seg_one.start
seg_two.start
seg_one.join
seg_two.join
scala.math.pow(acc, 1.0 / p)
}
println(parallelpNorm(toSum, 2))
Expected output is 9.5393920142 but instead some runs give me 9.273618495495704 or even 2.23606797749979.
Any recommendations where the race condition could happen?
The problem has been explained in the previous answer, but a better way to avoid this race condition and improve performance is to use an AtomicInteger
// Calculate the p-norm over an Array a
def parallelpNorm(a: Array[Int], p: Double): Double = {
val acc = new AtomicInteger(0)
// The worker who should calculate the sum over a slice of an array
class sumSegmenter(s: Int, t: Int) extends Thread {
override def run() {
// Calculate the sum over the slice
val subsum = sumSegment(a, p, s, t)
// Add the sum of the slice to the accumulator in a synchronized fashion
acc.getAndAdd(subsum)
}
}
val split = a.length / 2
val seg_one = new sumSegmenter(0, split)
val seg_two = new sumSegmenter(split, a.length)
seg_one.start()
seg_two.start()
seg_one.join()
seg_two.join()
scala.math.pow(acc.get, 1.0 / p)
}
Modern processors can do atomic operations without blocking which can be much faster than explicit synchronisation. In my tests this runs twice as fast as the original code (with correct placement of x)
Move val x = new AnyRef{} outside sumSegmenter (that is, into parallelpNorm) -- the problem is that each thread is using its own mutex rather than sharing one.

How can i get my list in correct order

I have almost got it right but my order will be like this
1.1.0.98
1.1.0.65
1.1.0.134
1.1.0.103
so it seems that when a third number is on it goes below the second.
code
def url = "http://mylink/".toURL().text
def root = new XmlSlurper().parseText(url)
def mylist = []
root.data.'content-item'.each{node ->
mylist << node.resourceURI.text() + node.relativePath.text().getAt(1..-2).replaceAll('/', '-').plus('.nupkg')
}
def result = []
mylist .reverseEach {
result << it
}
result
No idea what you're asking, but you can make your code a lot simpler...
This should work:
def result = root.data.'content-item'.collect { node ->
node.resourceURI.text() +
node.relativePath.text()[1..-2].replaceAll('/', '-') +
'.nupkg'
}.reverse()
no need for myList or reverseEach

I need a shorthand way to combine Maps in groovy with slightly different results than +

NOTE: This can be done as a method call or an operator override pretty easily, I am looking for an intrinsic one-line solution that I don't have to carry around in a library.
When you combine(add) Maps, you get a result like this:
println [a:1,c:3] + [a:2]
// prints {a=2, c=3}
I seem to keep needing results more like:
{a=[1, 2], c=[3]}
In other words, something that combines all the values from identical keys in the Maps.
Is there an operator or simple function call that does this, because doing it myself always seems to break my stride a little. It seems like the * operator might do this nicely, but it doesn't.
Is there an easy way to do this?
Another alternative (adding it to the * operator on Maps)
def a = [ a:1, c:10 ]
def b = [ b:1, a:3 ]
Map.metaClass.multiply = { Map other ->
(delegate.keySet() + other.keySet()).inject( [:].withDefault { [] } ) { m, v ->
if (delegate[v] != null) { m[v] << delegate[v] }
if (other[v] != null) { m[v] << other[v] }
m
}
}
assert a * b == [a:[1, 3], c:[10], b:[1]]
Came up with this as well, but it's late and there are probably better, shorter ways
def a = [ a:1, c:10 ]
def b = [ b:1, a:3 ]
[a,b]*.collect {k,v -> [(k):v]}
.flatten()
.groupBy { it.keySet()[0]}
.inject([:].withDefault{[]}) {m,v->
m << [(v.key):v.value[v.key]]
}
​​
Nothing came to my mind, so I start the bidding with this:
m1 = [a:1, c:666]; m2 = [a:2, b:42]
result = [:].withDefault{[]}
[m1,m2].each{ it.each{ result[it.key] << it.value } }
assert result == [a:[1,2], b:[42], c:[666]]

Difference of two maps in groovy using collectEntries

I am trying to find the difference between values in two maps
#Test
void testCollecEntries() {
def mapOne= ["A":900,"B":2000,"C":1500]
def maptwo = ["A":1000,"D":1500,"B":1500]
def balanceMap = maptwo.collectEntries { key, value-> [key:value-mapOne[key]] }
println balanceMap
}
I am trying to find the difference of values from maptwo with that of the values from mapOne. If the entry doesn't exist i need to ignore. This gives me a null pointer exception.
Appreciate any help.
It will throw NPE because you are looking for key "D" in mapOne which is not available.
You can avoid that by a null safe operation and default value to 0.
def one= [A:900, B:2000, C:1500]
def two = [A:1000, D:1500, B:1500]
def result = two.collectEntries{k,v -> [k, (v - (one[k]?:0))]}
println result
//Print
[A:100, D:1500, B:-500]
In case, you want to consider the common keys then use:
def result = two.collectEntries{k,v -> one[k] ? [k, (v - one[k])] : [:]}
//or
//def result = two.collectEntries{k,v -> (k in one.keySet()) ? [k, (v - one[k])] : [:]}
//Print
[A:100, B:-500]
You could look at this good example: http://groovyconsole.appspot.com/script/364002

Create comma separated string from 2 lists the groovy way

What I have so far is:
def imageColumns = ["products_image", "procuts_subimage1", "products_subimage2", "prodcuts_subimage3", "products_subimage4"]
def imageValues = ["1.jpg","2.jpg","3.jpg"]
def imageColumnsValues = []
// only care for columns with values
imageValues.eachWithIndex { image,i ->
imageColumnsValues << "${imageColumns[i]} = '${image}'"
}
println imageColumnValuePair.join(", ")
It works but I think it could be better. Wish there was a collectWithIndex ... Any suggestions?
There's no collectWithIndex, but you can achieve the same result with a little effort:
def imageColumns = ["products_image", "procuts_subimage1", "products_subimage2", "prodcuts_subimage3", "products_subimage4"]
def imageValues = ["1.jpg","2.jpg","3.jpg"]
def imageColumnsValues = [imageValues, 0..<imageValues.size()].transpose().collect { image, i ->
"${imageColumns[i]} = '${image}'"
}
println imageColumnsValues.join(", ")
This takes the list of items and a range of numbers from 0 size(list) - 1, and zips them together with transpose. Then you can just collect over that result.

Resources