如何在Kotlin中按分隔符分割对象List为子列表?
Kotlin 按指定Token分割列表的优雅实现方式
我有一个Token对象的List,希望按指定分隔符将其分割为子列表,示例如下:
data class Token(val name: String, val `val`: String) val tokens = listOf( Token(name = "lorem", `val` = "ipsum"), Token(name = "dolor", `val` = "sit"), Token(name = "newline", `val` = "\n"), Token(name = "amet", `val` = "consectetur") )
分隔符为任何name属性为"newline"的Token,分割后结果应为:
listOf( listOf( Token(name = "lorem", `val` = "ipsum"), Token(name = "dolor", `val` = "sit") ), listOf( Token(name = "amet", `val` = "consectetur") ) )
我自己已经实现了这个功能,但想知道有没有更优雅的、内置的(首选函数式风格)实现方式?我正在学习Kotlin,从C++转过来后经常会重复造轮子。
优雅的函数式实现(基于标准库内置函数)
Kotlin标准库提供了fold函数,完全可以用它来实现这个需求,代码简洁且符合函数式风格,不需要自己造轮子:
val splitTokens = tokens.fold(mutableListOf(mutableListOf<Token>())) { acc, token -> if (token.name == "newline") { acc.add(mutableListOf()) } else { acc.last().add(token) } acc }.filterNot { it.isEmpty() }
代码说明:
fold的初始值是一个包含空可变列表的可变列表,用来存储最终的子列表集合- 遍历每个Token:如果是分隔符(
name为"newline"),就向结果集合中添加一个新的空列表;否则将当前Token加入到最后一个子列表中 - 最后用
filterNot移除可能出现的空列表(比如原列表开头或结尾是分隔符的情况,避免生成空的子列表)
如果需要不可变集合的版本,可以在最后转换为不可变List:
val splitTokens = tokens.fold(mutableListOf(mutableListOf<Token>())) { acc, token -> if (token.name == "newline") { acc.add(mutableListOf()) } else { acc.last().add(token) } acc }.filterNot { it.isEmpty() } .map { it.toList() } // 将每个子列表转为不可变List .toList() // 将外层集合转为不可变List
另外,如果你使用Kotlin 1.4及以上版本,也可以用buildList来实现,可读性更强:
val splitTokens = buildList { var current = mutableListOf<Token>() add(current) tokens.forEach { token -> if (token.name == "newline") { current = mutableListOf() add(current) } else { current.add(token) } } }.filterNot { it.isEmpty() }
这种写法利用buildList构建最终列表,逻辑和fold版本一致,代码更直观。
内容的提问来源于stack exchange,提问作者linguisician
相关产品推荐
相关产品推荐

