Reputation: 205
I've a observable that parse large csv file (can not fit in memory) and emits elements like :
[{id=1, childId=1}, {id=1, childId=2}, {id=1, childId=3}, {id=2, childId=5}, {id=2, childId=6}, {id=1, childId=23}, {id=1, childId=18}]
one item by line.
When using groupBy, my output is something like
[{id=1, childs=1,2,**323, 18**}, {id=2, childs=5,6}]
It seems normal for groupBy. But what I need is to receive grouped elements for consecutive items, so I want to receive last items with id=1 in another element. In total, I would like to receive 3 elements.
So I want to receive one observable for the same key in a consecutive way, and when I have a different key, I want to receive another observable (group by).
Thank you in advance
Upvotes: 0
Views: 500
Reputation: 2085
One of possible solutions is to write custom ObservableTransformer
.
In my opinion, the simplest solution is to split items in groups according to next rule: if cell.Id != previousCell.Id put it in another group.
data class Cell(val id: Int, val childId: Int)
Observable.fromIterable(cells)
.map(object: Function<Cell, Pair<Int, Cell>> {
var latest: Int? = null
var groupNumber: Int = 0
override fun apply(t: Cell): Pair<Int, Cell> {
if(t.id != latest) {
latest = t.id
groupNumber++
}
return Pair(groupNumber, t)
}
})
.groupBy { it.first }
After that all sequential cells with the same id
will be in one group. Now you can do whatever you want. To get output as you expected use next approach:
Observable.fromIterable(cells)
.map(object: Function<Cell, Pair<Int, Cell>> {
var latest: Int? = null
var groupNumber: Int = 0
override fun apply(t: Cell): Pair<Int, Cell> {
if(t.id != latest) {
latest = t.id
groupNumber++
}
return Pair(groupNumber, t)
}
})
.groupBy { it.first }
.flatMapSingle { group ->
return@flatMapSingle group.reduce(Pair(group.key!!, mutableListOf())) { acc: Pair<Int, MutableList<Int>>, el: Pair<Int, Cell> ->
acc.second.add(el.second.childId)
return@reduce acc
}
}.toList()
.subscribe({
Log.d("TAG", it.toString())
}, { e -> e.printStackTrace() })
Output will be [(1, [1, 2, 3]), (2, [5, 6]), (3, [23, 18])].
That solution is not clean, but it works as you need.
Upvotes: 1