【问题标题】:Functional Programming in Kotlin: Counting elements in list by using foldKotlin 中的函数式编程:使用折叠计算列表中的元素
【发布时间】:2022-01-19 12:43:02
【问题描述】:

我的任务是使用 fold(函数式编程)编写一个函数来计算列表中满足谓词的元素数量。我得到了函数签名fun <A> count(list<A>, predicate: (A) -> Boolean): Int。折叠不仅要用作迭代,还要生成返回值。所以我尝试这样做:

fun <A> count(list: List<A>, predicate: (A) -> Boolean): Int {
        return list.fold(0) {
            acc, a ->
            if (predicate(a)) {
                return acc + 1
            }

            return acc
        }
    }

我写了一个 println 来检查它是否有效:

println(count3(listOf (1, -2, 3, 10, -5, 8, 12), { it > 0 && it < 10 }))

但是,我在控制台上得到的结果是 1 而不是 3,我不知道问题出在哪里。那么,有没有人知道我的错误在哪里或者我可以如何实现该功能?

并且要明确一点:Fold 累加一个值,从初始值(在本例中为 0)开始,并将从左到右的操作应用于当前累加器和每个元素,还是我弄错了?

编辑(我希望可以编辑一个问题而不是问一个新问题):

是否可以返回整个列表而不仅仅是一个 int?我刚刚找到了返回整数或布尔值的示例。我尝试了什么: 我使用了上面相同的函数签名。但我不想返回一个 Int,而是返回一个列表:

fun <A> returnList(list: List<A>, predicate: (A) -> Boolean): List<A> {
        return list.fold(mutableListOf()) {
            acc, a ->
            if (predicate(a)) {
                acc.add(a)
            } else {
                acc
            }
        }
    }

我发现的问题是acc.add(a) 返回的是布尔值而不是列表,因此IDE 将其标记为错误。那么有没有办法返回一个列表呢?

提前致谢。

【问题讨论】:

    标签: list kotlin generics functional-programming fold


    【解决方案1】:

    通过说return,您返回整个count 函数。您可以改用return@fold。很喜欢

    fun <A> count(list: List<A>, predicate: (A) -> Boolean): Int {
        return list.fold(0) {
                acc, a ->
            if (predicate(a)) {
                return@fold acc + 1
            }
    
            return@fold  acc
        }
    }
    

    另外,也许更好的是这样做

    fun <A> count(list: List<A>, predicate: (A) -> Boolean): Int {
        return list.fold(0) {
                acc, a ->
            if (predicate(a)) {
                acc + 1
            } else {
                acc
            }
        }
    }
    

    lambda 中的最后一个表达式隐含地也是它的返回值

    【讨论】:

      【解决方案2】:

      试试这样:

      fun <A> count(list: List<A>, predicate: (A) -> Boolean): Int {
          return list.fold(0) { acc, a -> if (predicate(a)) acc+1 else acc }
      }
      
      fun main(args: Array<String>) {
          val x = listOf<Int>( 1, -2, 3, 10, -5, 8, 12);
          println(count(x, { it > 0 && it < 10 }))
      }
      

      查看this site 让我明白了必要的更改。

      这种形式是否必要,因为 fold 使用尾递归?看看是什么原因很有趣。

      【讨论】:

      • 不起作用,因为 acc + 1 是一个什么都不做的语句,正确的运算符应该是 += 1,但这是不可能的,因为 acc 是只读的。所以你需要一个 else 来进行隐式返回或在 acc+1 中添加一个 return 语句。
      • 已修复。这次答对了。
      【解决方案3】:
      fun <A> count(list: List<A>, predicate: (A) -> Boolean): Int {
        return list.fold(0) { acc, a -> acc + predicate(a).run { if (this) 1 else 0 } }
      }
      

      【讨论】:

        【解决方案4】:

        我在 kotlin-forum 中找到了如何使用折叠返回列表(请参阅我的问题编辑)的答案:

        而不是写:

        fun <A> returnList(list: List<A>, predicate: (A) -> Boolean): List<A> {
                return list.fold(mutableListOf()) {
                    acc, a ->
                    if (predicate(a)) {
                        acc.add(a)
                    } else {
                        acc
                    }
                }
            }
        

        你可以写(以下solution was provided by al3c在kotlin论坛):

        fun <A> returnList(list: List<A>, predicate: (A) -> Boolean): List<A> {
                return list.fold(mutableListOf()) {
                    acc, a ->
                    if (predicate(a)) {
                        acc.add(a)
                    } 
                    acc
                }
            }
        

        通过这样做,代码返回的不是单个整数、字符或布尔值,而是整个列表。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2015-02-09
          • 2019-11-02
          • 2015-08-25
          • 2021-03-09
          • 1970-01-01
          相关资源
          最近更新 更多