0
votes

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

1

1 Answers

1
votes

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.