【问题标题】:Partitioning consecutive elements of a list based on a predicate in functional style [duplicate]基于功能样式的谓词对列表的连续元素进行分区[重复]
【发布时间】:2020-12-26 21:50:14
【问题描述】:

我需要在 Kotlin 中实现一个函数:

fun <T> partitionConsecutiveWithPredicate(input : List<T>, pred : (T, T) -> Boolean) : List<List<T>>

当结果列表中的每个子列表都是原始列表中符合所提供谓词的一组连续元素时,该函数将输入列表划分为列表列表。

示例 #1 - 调用 Int 列表中的方法 [2, 2, 2, 2, 5, 5, 8, 2, 2, 3]
带有谓词{ t1 : Int, t2 : Int -&gt; t1 == t2}
应该导致[[2, 2, 2, 2], [5, 5], [8], [2, 2], [3]]

示例 #2 - 调用 Int 列表中的方法 [1, 2, 3, 4, 3, 2, 1, 2]
带有谓词{ t1 : Int, t2 : Int -&gt; t2 == t1 + 1}
应该导致[[1, 2, 3, 4], [3], [2], [1, 2]]

当然,我可以使用传统的 while 循环和列表操作库函数来实现这一点,但我想以纯粹的函数式风格来实现,即只使用 lambdas/sequences(不允许显式的 for/while 循环)。 我尝试使用 runningReduce 和 runningFold,但它在每个步骤中都会创建一个结果列表,这在这种情况下是不可取的(您应该仅在谓词不再满足时才创建一个子列表)。


编辑: 我注意到similar question 存在,但该问题并未强调需要功能性解决方案,因此我将保留此问题。

【问题讨论】:

  • 这是一个练习,还是用于生产?几乎可以肯定 可能 使用 fold-type 调用 - 尽管您可能需要先执行 zipWithNext() 之类的操作,以便知道何时开始新的子列表。但我怀疑它会更简单,更易于维护,在带有 while 循环的命令式风格中......
  • 这是一个练习。对于实现(命令式/函数式)没有施加任何限制,但我想尝试函数式的方式,因为命令式的方式非常简单。
  • 这能回答你的问题吗? Split a list based on condition in kotlin这个问题的标题没有“连续”,但应该有。将很快对其进行编辑。我相信这几乎是完全相同的副本。
  • @Fureeish 查看编辑
  • 好吧,如果该问题涵盖了您的问题中的内容并且该答案回答了您的问题,我建议接受重复标志。

标签: kotlin lambda functional-programming


【解决方案1】:

可能有更好的方法,一种方法是使用循环:

fun <T> partitionConsecutiveWithPredicate2(input: List<T>, pred: (T, T) -> Boolean): List<List<T>> {
    val result = mutableListOf<List<T>>()
    var currentList = mutableListOf<T>()
    input.forEachIndexed { i, el ->
        currentList.add(el)
        if (i + 1 >= input.size || !pred(el, input[i + 1])) {
            result.add(currentList.toList())
            currentList = mutableListOf()
        }
    }
    return result
}

这里的想法是累积 currentList 中的值,直到所有元素都被处理 (i + 1 &gt;= input.size) 或谓词不满足,在这种情况下 currentList 被添加到结果中并被清空。

kotlin Playground 中的可执行代码:https://pl.kotl.in/rv_Yq8WdG,具有功能和迭代版本。

或者使用fold:

fun <T> partitionConsecutiveWithPredicate(input: List<T>, pred: (T, T) -> Boolean)
    = input
        .fold(mutableListOf()) { acc: MutableList<MutableList<T>>, elem ->
            when {
                acc.lastOrNull() == null -> acc.add(mutableListOf(elem))
                acc.lastOrNull() != null -> acc.last().apply {
                    if (pred(last(), elem)) {
                        add(elem)
                    } else {
                        acc.add(mutableListOf(elem))
                    }
                }
            }
            acc
        }

kotlin Playground 中的可执行代码: https://pl.kotl.in/z_ccIgX5C

【讨论】:

  • 谢谢!这是一个优雅的解决方案,但不是那么实用,因为您可以用循环替换 mapIndexed 调用,这几乎是命令式的解决方案。
  • 好的,我还使用 fold 添加了另一个版本
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-01-15
  • 2021-08-23
  • 1970-01-01
相关资源
最近更新 更多