Transformasikan while loop menjadi closure di Groovy
Cara mengubah kode while berikut di groovy menjadi penutupan yang menarik. Apa itu mungkin ?
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"]
Saya memikirkan solusi berikut, tetapi sepertinya itu tidak berfungsi:
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"]
Saya mendapatkan komentar ini dalam kode saya di atas yang " index = index + 2tidak pernah digunakan"
Jawaban
Pertimbangkan injectmetodenya (meskipun ini mengubah elemen daftar, yang tampaknya tidak pasti):
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"]
Di sini, accadalah "daftar hasil yang terakumulasi" dan itemmerupakan item saat ini dalam daftar asli. Dari sini : injectmetode ini juga dikenal sebagai reduceatau folddalam bahasa lain.
Jawaban lain yang mirip dengan Michael Easter dengan suntikan:
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"]
dengan mungkin beberapa karakter lebih sedikit.
Ini solusi kedua saya. Itu tidak menggunakan closure tapi bisa dibilang "fungsional". Perhatikan bahwa ini bukan ide bagus untuk daftar besar:
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"]
Tidak yakin apakah ini yang paling grooviest dari semua solusi yang ada, tetapi ini berfungsi untuk contoh Anda:
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)}}
yang kembali [s1, s2, s3:s4, s5:]seperti yang diharapkan
Anda memproses setiap elemen dalam daftar dan
jika elemen sebelumnya ada dan berakhiran: tidak melakukan apa - apa
jika elemen saat ini dicadangkan dan bukan yang terakhir: gabungkan elemen saat ini dengan elemen berikutnya.