大きなリストを処理のためのバッチに分割するGroovy's collateに相当する機能を探しています。私はsubList
を見ましたが、これは同様の機能に適合させることができましたが、自分自身を圧延するための組み込みの、あるいはクレイジーな単純な方法を見逃していないことを確認したいと思いました。ここでKotlin:大きいリストを設定されたパーティションサイズのサブリストに変換する
答えて
は、コレクション、またはSequence
になり、最後の1は、そのサイズ以下であることと、List
そのサイズのそれぞれのSequence
を返すことができる何かを取る怠惰なバッチ処理拡張機能の実装です。
バッチとしてリストを反復する使用例:Set
にList
のバッチを変換する
myList.asSequence().batch(5).forEach { group ->
// receive a Sequence of size 5 (or less for final)
}
例:
myList.asSequence().batch(5).map { it.toSet() }
出力所与の特定を示す以下最初のテストケースを見ます入力。機能Sequence<T>.batch(groupSize)
ため
コード:
public fun <T> Sequence<T>.batch(n: Int): Sequence<List<T>> {
return BatchingSequence(this, n)
}
private class BatchingSequence<T>(val source: Sequence<T>, val batchSize: Int) : Sequence<List<T>> {
override fun iterator(): Iterator<List<T>> = object : AbstractIterator<List<T>>() {
val iterate = if (batchSize > 0) source.iterator() else emptyList<T>().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<Int>, batchSize: Int, expectedGroups: Int) {
var groupSeenCount = 0
var itemsSeen = ArrayList<Int>()
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<Int>().asSequence().batch(1).forEach { groupStream ->
fail()
}
}
}
明らかに、これは、 'it.toList()'にマップされている例のように、怠惰にすることはできません。シーケンスの代わりに 'Collection'から作業することもできます。しかし、それを 'Sequence'に変換するのは簡単なので、それは良い出発点です。 –
FYI:バッチコードにバグがあると思います。以下は、無限ループの 'listOf(1,2,3,4,5,6,7,8,9,10).asSequence().batch(2).toList()'に詰まっています。 – mfulton26
ええ、私はそれが今、要素が消費されず、リストに変換する場合、イテレータは依然として表示されることがわかります。イテレータを進めて、消費しないアイテムを保持するためのものを作成する必要があります。 –
私はどちらかkotlin-stdlib
の1が表示されません。 Guavaは詳細についてはCollectionUtilitiesExplained · google/guava Wikiを見ると、あなたが慣れていない場合
:私は(それがjava.util.List.subList(int, int)
を使用しています)google-guava
からLists.partition(List, int)を使用することをお勧めします。
したい場合は、それをあなた自身のKotlin extension functionを作成することができます。
fun <T> List<T>.collate(size: Int): List<List<T>> = Lists.partition(this, size)
を使用すると、変更可能なリストの拡張機能を使用する場合は、その後、別Kotlinファイル(プラットフォーム宣言の衝突を避けるために):
fun <T> MutableList<T>.collate(size: Int): List<MutableList<T>> = Lists.partition(this, size)
Jayson Minard's answerのような遅延ロードが必要な場合はIterables.partition(Iterable, int)を使用できます。最後のサブリストが指定されたsize
より小さい場合、そのサブリストを埋めたい場合は、Iterables.paddedPartition(Iterable, int)にも興味があります。これらの返信Iterable<List<T>>
(私は多くの点をIterable<Iterable<T>>
として表示されませんsubList
効率的なビューを返します)。
あなたはあなたが言及したsubList
機能を使用して、独自のかなり簡単にロールバックすることができグアバに依存したくない何らかの理由の場合:
fun <T> List<T>.collate(size: Int): List<List<T>> {
require(size > 0)
return if (isEmpty()) {
emptyList()
} else {
(0..lastIndex/size).map {
val fromIndex = it * size
val toIndex = Math.min(fromIndex + size, this.size)
subList(fromIndex, toIndex)
}
}
}
または
fun <T> List<T>.collate(size: Int): Sequence<List<T>> {
require(size > 0)
return if (isEmpty()) {
emptySequence()
} else {
(0..lastIndex/size).asSequence().map {
val fromIndex = it * size
val toIndex = Math.min(fromIndex + size, this.size)
subList(fromIndex, toIndex)
}
}
}
別々のファイルの代わりに '@ JvmName'を使うこともできます。詳細については、[@JvmNameでのシグネチャの衝突の処理](https://kotlinlang.org/docs/reference/java-to-kotlin-interop.html#handling-signature-clashes-with-jvmname)を参照してください。 – mfulton26
私は最後の短い答えが好きです。これはArrayListsでうまく動作し、バリエーションは配列に対してうまく機能します。他のリストは、パフォーマンスが低いかもしれない(すなわち、LinkedList)。他のコレクションでは不可能です。 –
あなたの答えを変更して、 'size'が0(div除算)または負であるときに行動を守ることができます。 –
より単純化/機能型ソリューションは
val items = (1..100).map { "foo_${it}" }
fun <T> Iterable<T>.batch(chunkSize: Int) =
withIndex(). // create index value pairs
groupBy { it.index/chunkSize }. // create grouping index
map { it.value.map { it.value } } // split into different partitions
items.batch(3)
注1:個人的には私はを好むでしょうここでメソッド名としてが使用されていますが、Kotlinのstdlibにはすでにリストが2つの部分に分割されています。
注2:Jaysonのイテレータソリューションは、大規模なコレクションの場合、このソリューションよりも拡張性があります。
あり、そのための組み込み関数は、まだ残念ながらありませんし、あなただけのList
秒のList
である必要がある場合は、機能や他の回答からSequence
ベースの実装は、素敵な眺めながら、私は、醜いの少しを書くことをお勧めしたいです命令的だが実行可能なコード。
これは私の最終的な結果である:
fun <T> List<T>.batch(chunkSize: Int): List<List<T>> {
if (chunkSize <= 0) {
throw IllegalArgumentException("chunkSize must be greater than 0")
}
val capacity = (this.size + chunkSize - 1)/chunkSize
val list = ArrayList<ArrayList<T>>(capacity)
for (i in 0 until this.size) {
if (i % chunkSize == 0) {
list.add(ArrayList(chunkSize))
}
list.last().add(this.get(i))
}
return list
}
Kotlin 1.2-M1で、あなたのニーズに応じて、あなたはあなたの問題を解決するには、次のいずれかの方法を選択できます。
#1。 chunked(size: Int)
fun main(args: Array<String>) {
val list = listOf(2, 4, 3, 10, 8, 7)
val newList = list.chunked(2)
//val newList = list.chunked(size = 2) // also works
print(newList)
}
/*
prints:
[[2, 4], [3, 10], [8, 7], [9]]
*/
#2を使用します。使用方法windowed(size: Int, step: Int)
fun main(args: Array<String>) {
val list = listOf(2, 4, 3, 10, 8, 7, 9)
val newList = list.windowed(2, 2)
//val newList = list.windowed(size = 2, step = 2) // also works
println(newList)
}
/*
prints:
[[2, 4], [3, 10], [8, 7], [9]]
*/
- 1. 「リストにリストされたデータポイント」リストの大きなリストをデータフレームに変換する
- 2. ネストされたリストのデータフレームを大きなデータフレームに変換する
- 3. 多次元リスト、あるサブリストの変更が他のサブリストに反映される
- 4. Kotlinのバイト数に大量に変換
- 5. 特定サブリストは完全に私は別のリストに一致する、リスト内のサブリストを検索したい
- 6. arangodb内のネストされたリスト(サブリスト)にデータを追加する
- 7. 私はkotlinでのLinkedListにリストを変換しようとしているkotlin
- 8. 可変サイズのサブリストのネストされたリストをSciPy配列にまとめる
- 9. Voraテーブルのパーティションサイズを設定するには?
- 10. リストをソートされたサブリストに分割する
- 11. サブリストのサブリストの抽出と新しいリストへの指定された範囲のグループ化
- 12. kotlinに変換されたjavaクラスファイルがコンパイルエラーを起こす
- 13. LVM Debianでパーティションサイズを正確に設定する方法は?
- 14. ネストされたリストのリスト(設定)?
- 15. 大きなデータフレーム列をリストに変換するには?
- 16. リストをリストのリストに追加すると、すべてのサブリストが変更されます
- 17. オブジェクトが格納されているリストのサブリストを作成するリスト
- 18. DataTableを厳密に型指定されたオブジェクトのリストに変換する
- 19. リスト内のサブリストを置き換えるにはどうすればいいですか?
- 20. 与えられたリストのサブリストのリストを作成します。
- 21. リストのサブリストを他のサブリストに分割する
- 22. Proxmox VMディスクファイルがプロビジョニングされた設定より大きい
- 23. javaをkotlinのペーストに変換する
- 24. ByteArrayOutputStreamをKotlinのjsonに変換する
- 25. Pythonはネストされたリストからサブリストを分離します
- 26. R:1つのレベルのリストにネストされたリストに変換
- 27. Linq:サブリストが別のリストに表示された回数をカウントする
- 28. アップロードされたcsvファイルをDjangoのリストに変換する
- 29. ランダム化されたクイックソート:低いパーティションサイズの確率1
- 30. Fタプルのリストをマップされたタプルのリストにシャープに変換する
この機能は、Kotlinの将来のバージョン用に提案されています。 https://github.com/Kotlin/KEEP/blob/master/proposals/stdlib/window-sliding.md – succcubbus