Transforme o loop while em encerramento no Groovy
Como transformar o seguinte código while em groovy em closures groovy. É possível ?
List<String> list = ["s1", "s2", "s3:", "s4", "s5"]
List<String> res = []
int index = 0
while (index < res.size()) {
String cur = list[index]
if (cur.endsWith(":")) {
String next = list[index + 1] /*out of bounds won't happen*/
res.add(cur + "\n" + next)
index = index + 2
} else {
res.add(cur)
index++
}
}
assert res == ["s1", "s2", "s3:s4", "s5"]
Pensei na seguinte solução, mas parece que não está funcionando:
List<String> list = ["s1", "s2", "s3:", "s4", "s5"]
List<String> res = list.eachWithIndex { int index, String cur ->
if (cur.endsWith(":")) {
String next = list[index + 1] /*Out of bounds won't happen*/
index = index + 2
return cur + "\n" + next
}
return cur
} as List<String>
assert res == ["s1", "s2", "s3:s4", "s5"]
Recebo esta observação no meu código acima de que " index = index + 2nunca é usado"
Respostas
Considere o injectmétodo (embora isso modifique elementos da lista, o que parece arriscado):
def list = ["s1", "s2", "s3:", "s4", "s5"]
def res = list.inject([], { acc, item ->
def lastItem = acc.isEmpty() ? null : acc.last()
if (lastItem?.endsWith(":")) {
acc[-1] += item
} else {
acc << item
}
acc
})
assert res == ["s1", "s2", "s3:s4", "s5"]
Aqui, accestá a "lista de resultados acumulados" e itemé o item atual na lista original. A partir daqui : o injectmétodo também é conhecido como reduceou foldem outras línguas.
Outra resposta semelhante à de Michael Easter com injetar:
def list = ["s1", "s2", "s3:", "s4", "s5"]
def res = list.inject([]) { acc, item ->
if (acc && acc[-1].endsWith(':'))
item = acc.removeLast() + item
acc + item
}
assert res == ["s1", "s2", "s3:s4", "s5"]
com talvez alguns personagens a menos.
Aqui está minha segunda solução. Não usa fechamentos, mas é indiscutivelmente "funcional". Observe que não é uma boa ideia para listas grandes:
def list = ["s1", "s2", "s3:", "s4", "s5"]
def str = list.join(",")
// e.g. s1,s2,s3:,s4,s5
str = str.replaceAll(/\:,/, ":")
// e.g. s1,s2,s3:s4,s5
def res = str.split(",")
assert res == ["s1", "s2", "s3:s4", "s5"]
Não tenho certeza se este é o grooviest de toda solução existente, mas funciona para o seu exemplo:
list = ["s1", "s2", "s3:", "s4", "s5:"]
res = []
list.eachWithIndex
{e, i -> if (i > 0 && list[i-1].endsWith(":")) {return}
if (e.endsWith(":") && i < list.size-1) {res.add("${e}${list[i+1]}") } else {res.add(e)}}
que retorna [s1, s2, s3:s4, s5:]como esperado
Você processa cada elemento da lista e
se o elemento anterior existe e é sufixado: não faça nada
se o elemento atual tiver o sufixo e não for o último: concatene o elemento atual com o próximo.