组合多个谓词不起作用

Combining multiple predicates not working

我正在尝试从列表中过滤出某些项目,然后按特定顺序将它们合并到最终列表中。第一个代码片段似乎效率低下,因为它创建了 2 个用于过滤的列表,然后迭代它们,但是该代码有效。第二个片段试图结合两个过滤,但是地图操作员没有将项目添加到 otherNums 列表

有人可以帮我理解为什么会这样吗?

片段 1:

fun main() {
    val favItem = 0
    val list = listOf(11, 12, 13, 2,3,4,5,6,7,10, favItem)
    
    val greaterThan10 = list.filter{item -> item > 10}
    val otherNums = list.asSequence().filter{item -> item != favItem}.filter{item -> item < 10}
    
    println(" $greaterThan10") //the list is filled with proper numbers
    
    println("merged list ${greaterThan10.plus(favItem).plus(otherNums)}")
}

结果:

 [11, 12, 13]
merged list [11, 12, 13, 0, 2, 3, 4, 5, 6, 7]

代码段 2:

fun main() {
    val favItem = 0
    val list = listOf(11, 12, 13, 2,3,4,5,6,7,10, favItem)
    
    val greaterThan10 = mutableListOf<Int>()
    val otherNums = list.asSequence().filter{item -> item != favItem}.map{
        if(it > 10) {
            greaterThan10.add(it)
        }
        it
    }
    .filter{item -> item != 10}
    
    println("$greaterThan10") // the list is empty
    
    println("merged list ${greaterThan10.plus(favItem).plus(otherNums)}")
}

结果:

 []
merged list [0, 11, 12, 13, 2, 3, 4, 5, 6, 7]
val favItem = 0
val list = listOf(11, 12, 13, 2, 3, 4, 5, 6, 7, 10, favItem)

val greaterThan10 = list.filter { it > 10 }
val otherNums = list - greaterThan10.toSet() - favItem

println("greaterThan10: $greaterThan10")   // [11, 12, 13]
println("otherNums: $otherNums")           // [2, 3, 4, 5, 6, 7, 10]
println("merged list: ${greaterThan10 + favItem + otherNums}")

编辑:将 .minus(...) 替换为 -。感谢@Ivo Beckers 的评论。

val favItem = 0
val list = listOf(11, 12, 13, 2, 3, 4, 5, 6, 7, 10, favItem)

val (greaterThan10, otherNums) = list           // destructuring assignment
  .filter { it != favItem }                     // filter out favItem
  .groupBy { it > 10 }                          // create two groups
  .toSortedMap { o1, _ -> if (o1) -1 else 1 }   // sort groups in the order [true, false]
  .map { it.value.toList() }                    // return the two lists

println("greaterThan10: $greaterThan10")
println("otherNums: $otherNums")
println("merged list: ${greaterThan10 + favItem + otherNums}")

在您的第二个代码段中,由于序列的惰性行为,greaterThan10 列表为空,仅当遇到 toList()sum() 等终端操作时才会迭代序列。

在你的例子中,序列在你写 .plus(otherNums) 时被迭代。 List + Sequence 产生 List。如果在打印合并列表后打印 greaterThan10 列表,您会发现它已填充。

顺便说一句,这里不需要 Sequence。序列比列表性能更高的两个主要情况是:

  • 当你有很多中间操作时,比如mapfilter等。 使用 Iterable 会创建大量中间 Iterable,这会消耗更多内存,
  • 当你在末尾进行某种短路操作时,如 take()contains()first() 等,即当不需要迭代整个集合来获得最终结果。

根据文档,

The lazy nature of sequences adds some overhead which may be significant when processing smaller collections or doing simpler computations. Hence, you should consider both Sequence and Iterable and decide which one is better for your case.

对于最终的解决方案,我认为你可以使用你的代码片段 1。我觉得这很好,只需删除不必要的 asSequence 并将两个 filter 合二为一。

fun main() {
    val favItem = 0
    val list = listOf(11, 12, 13, 2, 3, 4, 5, 6, 7, 10, favItem)
    
    val greaterThan10 = list.filter {item -> item > 10}
    val otherNums = list.filter { it != favItem && it <= 10 }
    
    println(" $greaterThan10")
    
    println("merged list ${greaterThan10 + favItem + otherNums}")
}

我认为在列表上使用 filterminus 更好,因为后者具有二次最坏情况时间复杂度(如果我没记错的话)。 我写了一个小例子来证明差异。 运行this多看几遍就知道区别了

此外,正如@IvoBeckers 在评论中提到的, “如果原始列表没有 favItem,此方法也会向其添加一个。如果列表有多个 favItem,此方法会将其替换为一个。”