Home > Blockchain >  Group items from list and sort it
Group items from list and sort it

Time:09-29

I have a list with items:

Header1, Item1, Item2, Item3,    Header2, Item4, Item5,    Header3, Item6, Item7

Every single header has title.

How I can group that elements into Header items, Header items etc. and sort it alphabetically by header title?

CodePudding user response:

I believe this problem isn't trivial to solve with functional-style transformations like group by, etc. Such operations are not that useful if we need to reference previous items in the collection.

I suggest using imperative style and good old loops:

fun Iterable<Base>.groupByHeader(): Map<Header, List<Item>> {
    val iter = iterator()
    if (! iter.hasNext()) {
        return emptyMap()
    }

    var currHeader = requireNotNull(iter.next() as? Header)
    var currItems = mutableListOf<Item>()
    val result = sortedMapOf(compareBy(Header::title), currHeader to currItems)
    iter.forEach { item ->
        when (item) {
            is Header -> {
                currHeader = item
                currItems = mutableListOf()
                result[currHeader] = currItems
            }
            is Item -> currItems.add(item)
            else -> throw IllegalArgumentException()
        }
    }
    return result
}

If we really like functional style then reduce/fold is probably our best option. We can use fold() in a similar way as above, but we can also utilize runningFold() like this:

fun Iterable<Base>.groupByHeader(): Map<Header, List<Item>> {
    return runningFold(Pair<Header?, Item?>(null, null)) { acc, item ->
        when (item) {
            is Header -> item to null
            is Item -> acc.first to item
            else -> throw IllegalArgumentException()
        }
    }.filter { it.first != null && it.second != null }
        .groupByTo(sortedMapOf(compareBy(Header::title)), { it.first!! }, { it.second!! })
}

This is shorter, but probably harder to understand, much less performant and it ignores Item objects placed at the beginning - first solution throws an exception in such a case.

  • Related