3

I have a function that can calculate the sum of numbers in array with condition like so:

func sumOfArrayWithCondition(array: [Int], filter: (element: Int) -> Bool) -> Int {
    var result = 0
    for i in 0..<array.count where filter(element: array[i]) {
        result += array[i] 
    }
    return result 
}

Now I want it to work with Int, Float, Double type. I have tried, but didn't work.

protocol Addable {
    func +(lhs: Self, rhs: Self) -> Self
}

extension Int: Addable {}
extension Double: Addable {}
extension Float: Addable {}

func sumOfArrayWithCondition<T: Addable>(array: [T], filter: (element: T) -> Bool) -> T {
    var result = 0
    for i in 0..<array.count where filter(element: array[i]) {
        result += array[i] // <-------- Error here
    }
    return result // <-------- Error here
}

But it says:

Binary operator '+=' cannot be applied to operands of type 'Int' and 'T'

So how to do it.

Any helps would be appreciated. Thanks.

1
  • 1
    The problem is that result is an Int. It should be a T. I also think you need to add func +=(inout lhs: Self, rhs: Self) to your protocol. Commented Jun 2, 2016 at 4:28

2 Answers 2

6

First issue is that the compiler is inferring the type Int for the var result because you don't declare a type and initialize it with 0. But you need result to be of type T.

First, in order to initialize result as an instance of type T with the value 0, you need to specify that Addable is also IntegerLiteralConvertible, which is already true for Int, Double and Float. Then you can declare result as type T and go from there.

As Rob pointed out, you also need to add the += function to your protocol if you want to be able to use it.

So the final code that achieves what you are looking for is:

protocol Addable : IntegerLiteralConvertible {
    func +(lhs: Self, rhs: Self) -> Self
    func +=(inout lhs: Self, rhs: Self)
}

extension Int: Addable {}
extension Double: Addable {}
extension Float: Addable {}

func sumOfArrayWithCondition<T: Addable>(array: [T], filter: (element: T) -> Bool) -> T {
    var result:T = 0
    for i in 0..<array.count where filter(element: array[i]) {
        result += array[i]
    }
    return result
}
Sign up to request clarification or add additional context in comments.

2 Comments

Thanks. Your answer really helps me.
You shouldn't do the ..< there. Just use direct iteration: for elem in array where filter(element: elem) { result += elem }. It's much cleaner that way
4

As Rob said, result is an Int. But there's no need to create that method at all. You're wanting to call that like so, based on your method signature:

let sum = sumOfArrayWithCondition(myArray, filter: myFilter)

instead, all you have to do is use existing methods provided by swift:

let sum = myArray.filter(myFilter).reduce(0) { $0 + $1 }

1 Comment

I forgot to tell you that I have tried this filter(myFilter).reduce(0) { $0 + $1 }, but I still want try to create a function similar like this :) (for learning). But as always, I will upvote your answer for your help.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.