我正在寻找一个与Groovy的collate相当的函数,它将大型List分成批处理.我确实看到subList
哪些可以改编成类似的功能,但想检查并确保我没有错过内置或疯狂的简单替代滚动我自己.
使用Kotlin 1.3,根据您的需要,您可以选择以下方法之一来解决您的问题.
chunked
fun main() { val list = listOf(2, 4, 3, 10, 8, 7, 9) val newList = list.chunked(2) //val newList = list.chunked(size = 2) // also works print(newList) } /* prints: [[2, 4], [3, 10], [8, 7], [9]] */
windowed
fun main() { val list = listOf(2, 4, 3, 10, 8, 7, 9) val newList = list.windowed(2, 2, true) //val newList = list.windowed(size = 2, step = 2, partialWindows = true) // also works println(newList) } /* prints: [[2, 4], [3, 10], [8, 7], [9]] */
注意: 对于Kotlin 1.2及更高版本,请参阅标准库中的chunked
和windowed
现在的功能.无需自定义解决方案.
这是一个懒惰的配料扩展功能,这将需要一个集合,或任何可以成为一个的实现Sequence
和返回Sequence
的List
每一个尺寸的,随着最后一个是该尺寸或更小.
将列表作为批处理迭代的示例用法:
myList.asSequence().batch(5).forEach { group -> // receive a Sequence of size 5 (or less for final) }
将批次转换List
为Set
:
myList.asSequence().batch(5).map { it.toSet() }
请参阅下面的第一个测试用例,以显示给定特定输入的输出.
功能代码Sequence
:
public funSequence .batch(n: Int): Sequence > { return BatchingSequence(this, n) } private class BatchingSequence
(val source: Sequence , val batchSize: Int) : Sequence > { override fun iterator(): Iterator
> = object : AbstractIterator
>() { val iterate = if (batchSize > 0) source.iterator() else emptyList
().iterator() override fun computeNext() { if (iterate.hasNext()) setNext(iterate.asSequence().take(batchSize).toList()) else done() } } }
单元测试证明它有效:
class TestGroupingStream { @Test fun testConvertToListOfGroupsWithoutConsumingGroup() { val listOfGroups = listOf(1, 2, 3, 4, 5, 6, 7, 8, 9, 10).asSequence().batch(2).toList() assertEquals(5, listOfGroups.size) assertEquals(listOf(1,2), listOfGroups[0].toList()) assertEquals(listOf(3,4), listOfGroups[1].toList()) assertEquals(listOf(5,6), listOfGroups[2].toList()) assertEquals(listOf(7,8), listOfGroups[3].toList()) assertEquals(listOf(9,10), listOfGroups[4].toList()) } @Test fun testSpecificCase() { val originalStream = listOf(1,2,3,4,5,6,7,8,9,10) val results = originalStream.asSequence().batch(3).map { group -> group.toList() }.toList() assertEquals(listOf(1,2,3), results[0]) assertEquals(listOf(4,5,6), results[1]) assertEquals(listOf(7,8,9), results[2]) assertEquals(listOf(10), results[3]) } fun testStream(testList: List, batchSize: Int, expectedGroups: Int) { var groupSeenCount = 0 var itemsSeen = ArrayList () testList.asSequence().batch(batchSize).forEach { groupStream -> groupSeenCount++ groupStream.forEach { item -> itemsSeen.add(item) } } assertEquals(testList, itemsSeen) assertEquals(groupSeenCount, expectedGroups) } @Test fun groupsOfExactSize() { testStream(listOf(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15), 5, 3) } @Test fun groupsOfOddSize() { testStream(listOf(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18), 5, 4) testStream(listOf(1,2,3,4), 3, 2) } @Test fun groupsOfLessThanBatchSize() { testStream(listOf(1,2,3), 5, 1) testStream(listOf(1), 5, 1) } @Test fun groupsOfSize1() { testStream(listOf(1,2,3), 1, 3) } @Test fun groupsOfSize0() { val testList = listOf(1,2,3) val groupCountZero = testList.asSequence().batch(0).toList().size assertEquals(0, groupCountZero) val groupCountNeg = testList.asSequence().batch(-1).toList().size assertEquals(0, groupCountNeg) } @Test fun emptySource() { listOf ().asSequence().batch(1).forEach { groupStream -> fail() } } }