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