【问题标题】:Combining multiple predicates not working组合多个谓词不起作用
【发布时间】:2022-01-06 06:23:41
【问题描述】:

我正在尝试从列表中过滤掉某些项目,并以特定顺序将它们合并到最终列表中。第一个代码 sn-p 似乎效率低下,因为它创建了 2 个用于过滤的列表然后迭代它们但是该代码有效。第二个 sn-p 试图结合这两个过滤但是 map 运算符没有将项目添加到 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]

【问题讨论】:

  • 您需要greaterThan10 列表还是只需要最后一个?
  • 不知道为什么,但删除 asSequence() 使得 greaterThan10 至少被填满
  • @JoãoDias 我需要最后一个,但greaterThan10 列表通过检查greaterThan10 中是否有正确的值来帮助调试
  • @IvoBeckers asSequence 有助于避免为每个 filter 创建 2 个单独的列表。效率更高一点
  • 是的,我明白了。但由于某种原因,如果你把它排除在外,大于 10 确实会被填满。而且我不明白为什么,因为在这两种情况下,greaterThan10.add(it) 在打印之前都会被调用

标签: kotlin collections predicate


【解决方案1】:

在您的第二个 sn-p 中,greaterThan10 列表是空的,因为序列的惰性行为,仅当遇到诸如 toList()sum() 之类的终端操作时才会迭代序列。

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

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

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

根据文档,

序列的惰性增加了一些开销,这在处理较小的集合或进行更简单的计算时可能很重要。因此,您应该同时考虑 Sequence 和 Iterable 并决定哪一个更适合您的情况。

对于最终的解决方案,我认为您可以使用您的 sn-p 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,此方法将用一个替换它。”

【讨论】:

  • 也许值得一提:如果原始列表没有 favItem 这个方法也会添加一个。而且我相信如果列表有多个 favItem 这个方法会用一个替换它。
  • 是的,你是对的。感谢您指出。将此添加到答案中。
【解决方案2】:
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 的评论。

【讨论】:

  • 我认为list.minus((greaterThan10 + favItem).toSet()) 比需要的更复杂。我相信一个简单的val otherNums = list - greaterThan10 - favItem 也一样好
  • 已编辑。非常感谢您的建议。更容易捕捉。
【解决方案3】:
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}")

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-10-07
    • 2012-04-06
    • 2011-04-16
    • 1970-01-01
    • 2018-01-20
    相关资源
    最近更新 更多