Transforma el bucle while en cierre en Groovy
Cómo transformar el siguiente código while en groovy en cierres geniales. Es posible ?
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"]
Pensé en la siguiente solución, pero parece que no funciona:
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"]
Recibo este comentario en mi código anterior que " index = index + 2nunca se usa"
Respuestas
Considere el injectmétodo (aunque esto muta elementos de la lista, lo que parece arriesgado):
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"]
Aquí, accestá la "lista de resultados acumulados" y itemes el elemento actual en la lista original. A partir de aquí : el injectmétodo también se conoce como reduceo folden otros idiomas.
Otra respuesta similar a la de Michael Easter con inyectar:
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"]
quizás con algunos personajes menos.
Aquí está mi segunda solución. No utiliza cierres, pero podría decirse que es "funcional". Tenga en cuenta que no es una gran idea 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"]
No estoy seguro de si esta es la solución más moderna de todas, pero funciona para su ejemplo:
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 regresa [s1, s2, s3:s4, s5:]como se esperaba
Procesas cada elemento de la lista y
si el elemento anterior existe y tiene el sufijo: no hacer nada
si el elemento actual tiene el sufijo y no es el último: concatenar el elemento actual con el siguiente.