2014-10-29 3 views
4

Приведен следующий список:Groovy: Добавить префикс для каждой строки в списке

List<String> list = ["test1", "test2", "test3"] 

Теперь я хочу, чтобы создать одну строку из этого списка в следующем формате:

"pre/test1 pre/test2 pre/test3" 

Так Я думал, я бы следующим образом:

println list.each { "pre/$it" }.join(' ') 

Однако это приводит к следующему выходу:

"test1 test2 test3" 

(Обратите внимание на недостающие префиксы.)
Как я могу достичь желаемой конкатенации в Groovy?

ответ

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

each возвращает немодифицированную коллекция - тогда collect коллекции возвращается с измененным содержанием.

+1

Хорошая маленькая хитрость. Не знал об этом! +1 – christopher

+1

Вот оно, спасибо! – Matthias

+0

Добро пожаловать. – Opal

1

Для больших списков (явно не тот случай) является более эффективным для формирования строки непосредственно:

def sb = ["test1", "test2", "test3"].inject(new StringBuilder()) { builder, value -> 
    builder << "pre/${value} " 
} 
sb.setLength(sb.size() - 1) // to trim the trailing space 

Оказывается, что скорее наоборот обстоит дело. Вот несколько тестовых прогонов с использованием 10 миллионов элементов, отслеживания процессора и в реальном времени через несколько прогонов:

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 
} 

И вот результаты:

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 
+1

У вас есть доказательства? –

+1

, по крайней мере, сохраняет промежуточный список. join использует сам StringBuilder, так что нет (t much of a) получить там? – cfrick

+0

@tim_yates, я думал, что в какой-то момент в недавнем прошлом я убедился в этом, но я должен забыть. Как вы можете видеть из моего обновленного ответа, я в основном ем свои слова. Я думаю, что я оставлю это в качестве напоминания о последствиях ухода из поляны перед миром. – BalRog