组合多个谓词不起作用

Posted

技术标签:

【中文标题】组合多个谓词不起作用【英文标题】: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.filteritem -> item > 10
    val otherNums = list.asSequence().filteritem -> item != favItem.filteritem -> 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().filteritem -> item != favItem.map
        if(it > 10) 
            greaterThan10.add(it)
        
        it
    
    .filteritem -> 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) 在打印之前都会被调用 【参考方案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")

【讨论】:

以上是关于组合多个谓词不起作用的主要内容,如果未能解决你的问题,请参考以下文章

谓词中的 Dtrace 字符串比较不起作用

ffmpeg:组合/合并多个 mp4 视频不起作用,输出仅包含第一个视频

基于 Key 和 Predicates 对 NSMutableArray 进行排序不起作用?

select2 多选不起作用

观察多个属性不起作用的Angular js

Bootstrapvalidator 在动态输入字段中不起作用