So I'm making a research on which method in groovy makes faster result.
Let's say we have:
def storage = [{item:"apple", amount:3, color: "red"}, {item:"mango", amount:5, color: "yellow"}]
Is doing this:
def someMap = [:]
storage.each {
someMap[it.item] = [amount: it.amount, color: it.color]
}
So when we need to get the amount of an item, we do this:
someMap["apple"].amount
Better than doing this? :
def storageFindByItem = { itemName ->
return storage.find{
i -> i.item == itemName
}
}
So when we need to get the amount of an item, we do this:
storageFindByItem("apple").amount
The short answer is that when it comes to performance assessments, you should perform your tests and decide from the results.
With that said, the first option searches an indexed map and would be presumably faster. But this is probably more likely when you're using a HashMap for someMap rather than [:] (LinkedHashMap). And of course this would take an additional amount of memory.
The second option will always be searching linearly whereas finding in a hash map runs in constant time.
All this could be speculation in the face of actual test results, which would really be encouraged.
Related
I cannot figure out why my function invokeAll does not give out the correct output/work properly. Any solutions? (No futures or parallel collections allowed and the return type needs to be Seq[Int])
def invokeAll(work: Seq[() => Int]): Seq[Int] = {
//this is what we should return as an output "return res.toSeq"
//res cannot be changed!
val res = new Array[Int](work.length)
var list = mutable.Set[Int]()
var n = res.size
val procedure = (0 until n).map(work =>
new Runnable {
def run {
//add the finished element/Int to list
list += work
}
}
)
val threads = procedure.map(new Thread(_))
threads.foreach(x => x.start())
threads.foreach (x => (x.join()))
res ++ list
//this should be the final output ("return res.toSeq")
return res.toSeq
}
OMG, I know a java programmer, when I see one :)
Don't do this, it's not java!
val results: Future[Seq[Int]] = Future.traverse(work)
This is how you do it in scala.
This gives you a Future with the results of all executions, that will be satisfied when all work is finished. You can use .map, .flatMap etc. to access and transform those results. For example
val sumOfAll: Future[Int] = results.map(_.sum)
Or (in the worst case, when you want to just give the result back to imperative code), you could block and wait on the future to get ahold of the actual result (don't do this unless you are absolutely desperate): Await.result(results, 1 year)
If you want the results as array, results.map(_.toArray) will do that ... but you really should not: arrays aren't really a good choice for the vast majority of use cases in scala. Just stick with Seq.
The main problem in your code is that you are using fixed size array and trying to add some elements using ++ (concatenate) operator: res ++ list. It produces new Seq but you don't store it in some val.
You could remove last line return res.toSeq and see that res ++ lest will be return value. It will be your work.length array of zeros res with some list sequence at the end. Try read more about scala collections most of them immutable and there is a good practice to use immutable data structures. In scala Arrays doesn't accumulate values using ++ operator in left operand. Array's in scala are fixed size.
I have a sequence of code points as Sequence<Int>.
I want to get this into a String.
What I currently do is this:
val string = codePoints
.map { codePoint -> String(intArrayOf(codePoint), 0, 1) }
.joinToString()
But it feels extremely hairy to create a string for each code point just to concatenate them immediately after. Is there a more direct way to do this?
So far the best I was able to do was something like this:
val string2 = codePoints.toList().toIntArray()
.let { codePoints -> String(codePoints, 0, codePoints.size) }
The amount of code isn't really any better, and it has a toList().toIntArray() which I'm not completely fond of. But it at least avoids the packaging of everything into dozens of one-code-point strings, and the logic is still written in the logical order.
You can either go for the simple:
val string = codePoints.joinToString("") { Character.toString(it) }
// or
val string = codePoints.joinToString("", transform = Character::toString)
Or use a string builder:
fun Sequence<Int>.codePointsToString(): String = buildString {
this#codePointsToString.forEach { cp ->
appendCodePoint(cp)
}
}
This second one expresses exactly what you want, and may benefit from future optimizations in the string builder.
it feels extremely hairy to create a string for each code point just to concatenate them immediately after
Did you really measure a performance issue with the extra string objects created here? Using toList() would also create a bunch of object arrays behind the scenes (one for each resize), which is a bit less, but not tremendously better. And as you pointed out toIntArray on top of that is yet another array creation.
Unless you know the number of elements in the sequence up front, I don't believe there is much you can do about that (the string builder approach will also likely use a resizable array behind the scenes, but at least you don't need extra array copies).
val result = codePoints.map { Character.toString(it) }.joinToString("")
Edit, based on Joffrey's comment below:
val result = codePoints.joinToString("") { Character.toString(it) }
Additional edit, full example:
val codePoints: Sequence<Int> = sequenceOf(
'a'.code,
Character.toCodePoint(0xD83D.toChar(), 0xDE03.toChar()),
Character.toCodePoint(0xD83D.toChar(), 0xDE04.toChar()),
Character.toCodePoint(0xD83D.toChar(), 0xDE05.toChar())
)
val result = codePoints.joinToString("") { Character.toString(it) }
println(result)
This will print: a😃😄😅
I need to create a string from a array of map in groovy.
Required string = ^(123|456|789)
At present I am doing something like below, will this cause performance issue in production box or should I use StringBuffer java class?
def getProjectList(def caseResult) {
def projectList = ""
caseResult.each { projno ->
if (projectList.length() == 0) {
projectList = "^(${projno.project_no}|"
} else {
if (projectList.indexOf(projno.project_no) == -1)
projectList+="${projno.project_no}|"
}
}
projectList = projectList.substring(0, projectList.length() - 1)
projectList += ')'
return projectList
}
I'd go for ease of reading...
def getProjectList(def caseResult) {
"^(${caseResult.project_no.join('|')})"
}
Actually, you just want the unique ones don't you?
def getProjectList(def caseResult) {
"^(${caseResult.project_no.unique().join('|')})"
}
I need to create a string from a array of map in groovy.
It would be extremely useful to define parameter type then.
The return type too.
will this cause performance issue in production box
Well, define performance issue first. Have you measured anything to think your code has any performance issues? If not, it looks like a typical "premature optimization"
should I use StringBuffer java class
If you worry about performance, then you should rather use StringBuilder, as StringBuffer is thread-safe, taking a little performance hit.
If your code suffers from anything, it's rather readability than performance.
And I recommend you this StackExchange site, dedicated to such questions - https://codereview.stackexchange.com/ - give it a try!
"When you've found the treasure, stop digging!"
I'm wanting to use more functional programming in Groovy, and thought rewriting the following method would be good training. It's harder than it looks because Groovy doesn't appear to build short-circuiting into its more functional features.
Here's an imperative function to do the job:
fullyQualifiedNames = ['a/b/c/d/e', 'f/g/h/i/j', 'f/g/h/d/e']
String shortestUniqueName(String nameToShorten) {
def currentLevel = 1
String shortName = ''
def separator = '/'
while (fullyQualifiedNames.findAll { fqName ->
shortName = nameToShorten.tokenize(separator)[-currentLevel..-1].join(separator)
fqName.endsWith(shortName)
}.size() > 1) {
++currentLevel
}
return shortName
}
println shortestUniqueName('a/b/c/d/e')
Result: c/d/e
It scans a list of fully-qualified filenames and returns the shortest unique form. There are potentially hundreds of fully-qualified names.
As soon as the method finds a short name with only one match, that short name is the right answer, and the iteration can stop. There's no need to scan the rest of the name or do any more expensive list searches.
But turning to a more functional flow in Groovy, neither return nor break can drop you out of the iteration:
return simply returns from the present iteration, not from the whole .each so it doesn't short-circuit.
break isn't allowed outside of a loop, and .each {} and .eachWithIndex {} are not considered loop constructs.
I can't use .find() instead of .findAll() because my program logic requires that I scan all elements of the list, nut just stop at the first.
There are plenty of reasons not to use try..catch blocks, but the best I've read is from here:
Exceptions are basically non-local goto statements with all the
consequences of the latter. Using exceptions for flow control
violates the principle of least astonishment, make programs hard to read
(remember that programs are written for programmers first).
Some of the usual ways around this problem are detailed here including a solution based on a new flavour of .each. This is the closest to a solution I've found so far, but I need to use .eachWithIndex() for my use case (in progress.)
Here's my own poor attempt at a short-circuiting functional solution:
fullyQualifiedNames = ['a/b/c/d/e', 'f/g/h/i/j', 'f/g/h/d/e']
def shortestUniqueName(String nameToShorten) {
def found = ''
def final separator = '/'
def nameComponents = nameToShorten.tokenize(separator).reverse()
nameComponents.eachWithIndex { String _, int i ->
if (!found) {
def candidate = nameComponents[0..i].reverse().join(separator)
def matches = fullyQualifiedNames.findAll { String fqName ->
fqName.endsWith candidate
}
if (matches.size() == 1) {
found = candidate
}
}
}
return found
}
println shortestUniqueName('a/b/c/d/e')
Result: c/d/e
Please shoot me down if there is a more idiomatic way to short-circuit in Groovy that I haven't thought of. Thank you!
There's probably a cleaner looking (and easier to read) solution, but you can do this sort of thing:
String shortestUniqueName(String nameToShorten) {
// Split the name to shorten, and make a list of all sequential combinations of elements
nameToShorten.split('/').reverse().inject([]) { agg, l ->
if(agg) agg + [agg[-1] + l] else agg << [l]
}
// Starting with the smallest element
.find { elements ->
fullyQualifiedNames.findAll { name ->
name.endsWith(elements.reverse().join('/'))
}.size() == 1
}
?.reverse()
?.join('/')
?: ''
}
What I've seen in Java
Java 8 allows lazy evaluation of chained functions in order to avoid performance penalties.
For instance, I can have a list of values and process it like this:
someList.stream()
.filter( v -> v > 0)
.map( v -> v * 4)
.filter( v -> v < 100)
.findFirst();
I pass a number of closures to the methods called on a stream to process the values in a collection and then only grab the first one.
This looks as if the code had to iterate over the entire collection, filter it, then iterate over the entire result and apply some logic, then filter the whole result again and finally grab just a single element.
In reality, the compiler handles this in a smarter way and optimizes the number of iterations required.
This is possible because no actual processing is done until findFirst is called. This way the compiler knows what I want to achieve and it can figure out how to do it in an efficient manner.
Take a look at this video of a presentation by Venkat Subramaniam for a longer explanation.
What I'd like to do in Groovy
While answering a question about Groovy here on StackOverflow I figured out a way to perform the task the OP was trying to achieve in a more readable manner. I refrained from suggesting it because it meant a performance decrease.
Here's the example:
collectionOfSomeStrings.inject([]) { list, conf -> if (conf.contains('homepage')) { list } else { list << conf.trim() } }
Semantically, this could be rewritten as
collectionOfSomeStrings.grep{ !it.contains('homepage')}.collect{ it.trim() }
I find it easier to understand but the readability comes at a price. This code requires a pass of the original collection and another iteration over the result of grep. This is less than ideal.
It doesn't look like the GDK's grep, collect and findAll methods are lazily evaluated like the methods in Java 8's streams API. Is there any way to have them behave like this? Is there any alternative library in Groovy that I could use?
I imagine it might be possible to use Java 8 somehow in Groovy and have this functionality. I'd welcome an explanation on the details but ideally, I'd like to be able to do that with older versions of Java.
I found a way to combine closures but it's not really what I want to do. I'd like to chain not only closures themselves but also the functions I pass them to.
Googling for Groovy and Streams mostly yields I/O related results. I haven't found anything of interest by searching for lazy evaluation, functional and Groovy as well.
Adding the suggestion as an answer taking cfrick's comment as an example:
#Grab( 'com.bloidonia:groovy-stream:0.8.1' )
import groovy.stream.Stream
List integers = [ -1, 1, 2, 3, 4 ]
//.first() or .last() whatever is needed
Stream.from integers filter{ it > 0 } map{ it * 4 } filter{ it < 15 }.collect()
Tim, I still know what you did few summers ago. ;-)
Groovy 2.3 supports jdk8 groovy.codehaus.org/Groovy+2.3+release+notes. your example works fine using groovy closures:
[-1,1,2,3,4].stream().filter{it>0}.map{it*4}.filter{it < 100}.findFirst().get()
If you can't use jdk8, you can follow the suggestion from the other answer or achieve "the same" using RxJava/RxGroovy:
#Grab('com.netflix.rxjava:rxjava-groovy:0.20.7')
import rx.Observable
Observable.from( [-1, 1, 2, 3, 4, 666] )
.filter { println "f1 $it"; it > 0 }
.map { println "m1 $it"; it * 4 }
.filter { println "f2 $it"; it < 100 }
.subscribe { println "result $it" }