Kotlin: Iterator in custom order

Viewed 1595

I need to iterate through a list of sets in a custom order, namely with ascending cardinality. Can a iterator with custom order be created in Kotlin?

2 Answers

Sure it is possible. Creating custom iterators is possible in Kotlin since... Java. You can take this code as a base:

class ListOfSets<E, S : Set<E>>(val from: List<S>) : Iterable<S> {
    override fun iterator(): Iterator<S> {
        return object : Iterator<S> {
            val state = from.sortedBy { it.size }
            var i = 0;

            override fun hasNext(): Boolean = i < state.size

            override fun next(): S = state[i++]
        }
    }
}

fun main() {
    val sets = ListOfSets(
            listOf(
                    setOf(1, 2, 3),
                    emptySet(),
                    setOf(1, 2, 3, 4),
                    setOf(1, 2),
                    setOf(1, 2, 1),
                    setOf(2, 2, 2, 2, 2)
            )
    )

    for (set in sets) {
        println(set)
    }
}

It prints:

[]
[2]
[1, 2]
[1, 2]
[1, 2, 3]
[1, 2, 3, 4]

The better question to ask yourself here is: why do you need an iterator instead of just sorting the collection with sortedBy directly where it's needed?

I think this is possible, but highly undesired due to how much internal work would have to be done inside a (in principle) lightweight abstraction of an interator.

How about creating an extension function that will give you a wrapper list that's sorted based on inner Sets' sizes, instead?

private fun <T> ArrayList<Set<T>>.sortedOnSizes(): List<Set<T>> = sortedBy {
    it.size
}

fun main() {
    val sets = ArrayList<Set<Int>>()
    sets.add(HashSet(setOf(1, 2, 3)))
    sets.add(HashSet(setOf(3)))
    sets.add(HashSet(setOf(1, 2, 3, 4, 5)))

    sets.sortedOnSizes().forEach(::println)
}

This prints:

[3]
[1, 2, 3]
[1, 2, 3, 4, 5]
Related