Functional Programming in Kotlin: Counting elements in list by using fold

Viewed 172

I've got the task to write a function using fold (functional programming) to count the number of elements in a list that fulfill the predicate. I was given the function signature fun <A> count(list<A>, predicate: (A) -> Boolean): Int. Fold shall not only be used as iteration, but also generate the return value. So I tried to do this:

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

            return acc
        }
    }

I wrote a println to check if it works:

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

However, I got the result 1 instead of 3 on the console and I don't know where the fault is. So, does anyone have an idea where my error is or how I can implement the function instead?

And just to be clear: Fold accumulates a value, starting with the initial value (in this case 0) and applying the operation from left to right to the current accumulator and each element or am I mistaken?

EDIT (I hope it's okay to edit a question instead of asking a new one):

Is it possible to return a whole list instead of just an int? I just found examples returning integers or booleans. What I tried: I've used the same function signature from above. But instead of return an Int, I want to return a list:

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

The problem that I found is that acc.add(a) returns a boolean and not a list, so that the IDE marks it as a mistake. So is there a way to return a list?

Thanks in Advance.

4 Answers

Try it like this:

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

Looking at this site made the necessary change clear to me.

Is that form necessary because fold uses tail recursion? Interesting to see what the reason is.

By saying return you return the entire count function. you can use return@fold instead. so like

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

alternatively and maybe better is to do it like this

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

the last expression in a lambda is implicitly also its return value

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

I found the answer how to return a list (see my question edit) with fold in the kotlin-forum:

Instead of writing:

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

You can write (the following solution was provided by al3c in the 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)
            } 
            acc
        }
    }

By doing so, the code returns not a single integer, character or boolean, but the whole list.

Related