Given is the following list:
List<String> list = ["test1", "test2", "test3"]
Now I want to create one String out of this list in the following format:
"pre/test1 pre/test2 pre/test3"
So I thought I would go the following way:
println list.each { "pre/$it" }.join(' ')
However, this leads to the following output:
"test1 test2 test3"
(Note the missing prefixes.)
How can I achieve the desired string concatenation in Groovy?
For large lists (clearly not the case here) it is more efficient to form the string directly:
def sb = ["test1", "test2", "test3"].inject(new StringBuilder()) { builder, value ->
builder << "pre/${value} "
}
sb.setLength(sb.size() - 1) // to trim the trailing space
It turns out that rather the opposite is the case. Here are some test runs using 10 million elements, tracking CPU and Real time across multiple runs:
import java.lang.management.ManagementFactory
def threadMX = ManagementFactory.threadMXBean
assert threadMX.currentThreadCpuTimeSupported
threadMX.threadCpuTimeEnabled = true
def timeCPU = { Closure c ->
def start = threadMX.currentThreadCpuTime
def result = c.call()
def end = threadMX.currentThreadCpuTime
println "CPU time: ${(end - start)/1000000000} s"
}
def timeReal = { Closure c ->
def start = System.currentTimeMillis()
def result = c.call(args)
def end = System.currentTimeMillis()
println "Elapsed time: ${(end - start)/1000} s"
result
}
def theList = (0..<10000000). collect { it.toString() }
[CPU:timeCPU, Real:timeReal].each { label, time ->
println "\n\n$label Time"
print ("Mine: ".padLeft(20))
def s2 = time {
def sb = theList.inject(new StringBuilder()) { builder, value ->
builder << "pre/${value} "
}
sb.setLength(sb.size() - 1)
sb.toString()
}
print ("cfrick's: ".padLeft(20))
def s3 = time {
def sb = theList.inject(new StringBuilder()) { builder, value ->
builder << "pre/" << value << " "
}
sb.setLength(sb.size() - 1)
sb.toString()
}
print ("Opal's: ".padLeft(20))
def s1 = time { theList.collect { "pre/${it}" }.join(" ") }
print "Opal's w/o GString: "
def s4 = time { theList.collect { "pre/" + it }.join(" ") }
assert s1 == s2 && s2 == s3 && s3 == s4
}
And here are the results:
CPU Time
Mine: CPU time: 12.8076821 s
cfrick's: CPU time: 2.1684139 s
Opal's: CPU time: 3.5724229 s
Opal's w/o GString: CPU time: 3.1356201 s
Real Time
Mine: Elapsed time: 15.826 s
cfrick's: Elapsed time: 3.587 s
Opal's: Elapsed time: 8.906 s
Opal's w/o GString: Elapsed time: 6.296 s
def joined = ["test1", "test2", "test3"].collect { "pre/$it" }.join(' ')
each
returns unmodified collection - whereas collect
returns collection with modified content.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With