按n个条件对集合进行分组

时间:2019-01-11 15:26:26

标签: kotlin

在Kotlin中,对具有n分组条件的元素进行分组的一种整洁(最好是功能性)的方式是什么?

例如:

class Item(val level : Int)

给出列表:(Item(1), Item(2), Item(5))

和两个分组条件:

  1. level > 0 && level < 3
  2. level > 4

预期以下列表:

  1. listOf(Item(1), Item(2))
  2. listOf(Item(5))

groupBy函数仅接受1个条件参数。还有其他有用的功能吗?

3 个答案:

答案 0 :(得分:5)

您可以在传递给Int的lambda中返回groupBy,以标识您的条件。这适用于任何条件。

val l = listOf(Item(1), Item(2), Item(5))

val g = l.groupBy {
    when {
        it.level > 0 && it.level < 3 -> 0
        it.level > 4 -> 1
        // ...
        else -> null
    }
}.filterKeys { it != null }) // optional: filter out null as default key

结果:

  

{0 = [Item(level = 1),Item(level = 2)],1 = [Item(level = 5)]}

答案 1 :(得分:0)

尝试filter淘汰所有不必要的元素,然后groupBypartition它们,例如:

使用partition(即,您只需要1个列表中的2个):

listSequence()
  .filter { it.level > 0 && it.level != 3 } // it seems you are only interested in levels > 0 && != 3
  .partition { it.level in 1..2 } // partition into items having 0 < level < 3 and the rest
  .run(::println) // prints: [[Item(level=1), Item(level=2)], [Item(level=5)]] (which is a pair of lists)

使用groupBy类似于Willi Mentzel所示:

listSequence()
    .filter { it.level > 0 && it.level != 3 } // if you need to filter... otherwise skip that and assign just a random group
    .groupBy { 
       when (it.level) {
         in 1..2 -> 0
         else -> 1
       }
    }
    .values.run(::println) // which also prints ([Item(level=1), Item(level=2)], [Item(level=5)]) but now is a collection of lists

在两种情况下,我都使用如下序列:

fun listSequence() = sequenceOf(Item(1), Item(2), Item(5), Item(-4), Item(0))

取决于最终要完成的工作...您可能会对其他可用的collection functions感兴趣。

答案 2 :(得分:0)

在这里,我还建议使用partion。您也可以将它们链接起来:

val cond1: (Item) -> Boolean = { it.level in 0..2 }
val cond2: (Item) -> Boolean = { it.level > 4 }
val parts = elements
    .partition { cond1(it) || cond2(it) }
    .first.partition { cond1(it) }
println(parts)

这将导致输入的迭代效率比groupBy略低。仍然是线性的运行时复杂度。