Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Groovy: Add prefix to each String in a List

Tags:

groovy

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?

like image 770
Matthias Avatar asked Oct 29 '14 15:10

Matthias


2 Answers

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
like image 35
BalRog Avatar answered Nov 16 '22 03:11

BalRog


def joined = ["test1", "test2", "test3"].collect { "pre/$it" }.join(' ')

each returns unmodified collection - whereas collect returns collection with modified content.

like image 91
Opal Avatar answered Nov 16 '22 01:11

Opal