I have a function with a for-loop:
fun List<Int>.customSum(sumFunction: (Int) -> Boolean): Int {
var sum = 0
for (item in this) {
if (sumFunction(item))
sum = item
}
return sum
}
I want to know how I can write the above in functional style. I know that I have to use this.reduce()
, but don't know exactly how to implement it.
CodePudding user response:
return filter(sumFunction).sum()
Should be self-explanatory.
You can’t use reduce because it doesn’t let you reject the first element.
With fold it would be:
return fold(0) { a, b ->
if(sumFunction(b)) a b else a
}
CodePudding user response:
I can think if two ways to achieve that:
- The first one is by using
sumOf {...}
:
.
fun List<Int>.customSum(sumFunction: (Int) -> Boolean): Int {
return sumOf {
if (sumFunction(it)) it else 0
}
}
- The second one is by using
filter {...}
thensum()
:
.
fun List<Int>.customSum(sumFunction: (Int) -> Boolean): Int {
return filter(sumFunction).sum()
}
CodePudding user response:
return this.reduce { sum, n -> if (sumFunction(n)) sum n else 0}
CodePudding user response:
If you really want to use reduce
for some reason you can - but you need to add that 0 to the head of the list as your "start state":
fun List<Int>.customSum(sumFunction: (Int) -> Boolean): Int {
val stuff = listOf(0) this
return stuff.reduce { a, b -> a if (sumFunction(b)) b else 0 }
}
You have to do that because reduce
is really there to combine a bunch of items, which is why for the first iteration you get the first two items in the list. You don't get to handle them separately, which is why you need to throw that 0 in there to get past that first step, and get to a point where you can just do your checking on the second parameter and ignore the first one, treating it as an accumulator instead of another item you also need to check.
That behaviour is what fold
is for - with that function you pass in an initial state (which can be a completely different type from your items, since you're not just smushing them together to create a new value like with reduce
) and then on each iteration you get that state and an item.
You can handle the item as you like, and then make changes to the accumulator state depending on the result. Which is exactly the behaviour of your for
loop! fold
is just a functional way to write one. Tenfour04's answer is how you'd do it - it's the right tool for the job here!