Kotlin中的函数式编程:使用fold计算列表中的元素数量。

3

我被分配了一个任务,使用fold(函数式编程)编写一个函数来计算符合谓词条件的列表中元素的数量。 我被给出了函数签名fun <A> count(list<A>, predicate: (A) -> Boolean): Int。 Fold不仅可以用作迭代,还可以生成返回值。 所以我尝试了以下代码:

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,并且我不知道哪里出了问题。那么,有没有人知道我的错误在哪里或者我该如何实现该函数呢?

仅为明确起见:折叠累积一个值,从初始值(在这种情况下为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将其标记为错误。是否有一种方法可以返回一个列表?
提前致谢。
4个回答

4
通过使用 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函数中的最后一个表达式隐式地也是它的返回值


3

试着像这样做:

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 }))
}

看了这个网站后,我清楚了所需的更改。

那个表单是否必要是因为fold使用尾递归?很有趣,想知道原因是什么。


无法工作,因为acc + 1是一个什么也不做的语句,正确的运算符应该是+= 1,但这是不可能的,因为acc是只读的。所以你需要一个else来进行隐式返回,或者在acc + 1中添加一个return语句。 - somethingsomething
修复了。这次得到了正确的答案。 - duffymo

0
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 } }
}

0

我在 Kotlin 论坛中找到了如何使用 fold 返回列表的答案(请参见我的问题编辑):

不要写成:

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
            }
        }
    }

你可以在 Kotlin 论坛中写下以下内容(解决方案由 al3c 提供):

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

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接