2

i have an array, var hoursPlayed = String they are in a tableView and are all numbers, how would i add the numbers in that array together to get the average of hours played????? in Swift 2

1

4 Answers 4

2

You could use reduce:

let sum= hoursPlayed.reduce(0.0,combine:{$0+Float($1)!})

Basically you are iterating through the array and accumulating all the values. Since it is an array of strings,for simplicity I've force unwrapped to a Float, but you must check for the optional. The reduce function takes a closure as argument with 2 parameters. The dollar sign means take the first and the second and sum them. Now you can easily divide to the number of elements in the array to have an avergae.
If you are in objC world it would be nice use key value coding and the @avg operator.
[UPDATE]
As Darko posted out the first version won't compile. The error was converting the first argument to a Float, since reduce takes an initial value and I put it as Float there is no need for further conversion.

Sign up to request clarification or add additional context in comments.

2 Comments

the basic idea is of course correct but it does not compile.
Sorry I'm writing on iPad, when I will be in my office I edit
2
let array = ["10.0", "30.0"]
if array.count > 0 {
    let average = array.reduce(0.0, combine: {$0 + (Double($1) ?? 0.0)}) / Double(array.count)
    print(average) // 20.0
}

$0 does not need to be converted because it is guaranteed that it's always Double. $0 is inferred from the initial value, which is declared as 0.0: Double.

array.count has to be checked to guard against a division thru 0.

1 Comment

This is a nice illustration of idiomatic Swift. The use of ?? is much better than forced unwrapping. Nicely done. (Comment should be changed to 20.0, though, as you correctly produce a Double not a String.)
1

I'd use a combination of flatMap to convert the strings to Doubles and reduce to add them up:

let doubles = array.flatMap { Double($0) }
let average = doubles.reduce(0.0, combine:+) / Double(doubles.count)

Using flatMap protects you from entries in array that can't be converted to Double If you know they all convert you can simplify it to:

let average = array.map({ Double($0)! }) / Double(array.count)

One final option is to extend Array with an average function if that seems like something you'll be more generally using, and use it in combination with flatMap and/or map:

protocol ArithmeticType {
    static func zero() -> Self

    func +(lhs:Self, rhs:Self) -> Self
    func -(lhs:Self, rhs:Self) -> Self
    func /(lhs:Self, rhs:Self) -> Self
    func *(lhs:Self, rhs:Self) -> Self

    init(_ number:Int)
}

extension Double : ArithmeticType {
    static func zero() -> Double {
        return 0.0
    }
}

extension Array where Element : ArithmeticType {
    func average() -> Element {
        return reduce(Element.zero(), combine:+) / Element(count)
    }
}

let avg = array.flatMap { Double($0) }.average()

2 Comments

The flatMap version looks very clean and intuitive. The only downside - it needs iterating twice over the array. But in most situations's in app development this is negligible and I would prefer readability over performance. +1
At least one version used lazy to do the iteration only once and avoid creating multiple arrays.
1

Modified Darko's approach, which take in account if String is convertible to Double, or not. For an empty array it returns 0.0

let array = ["10.0", "31.2", "unknown", ""]

func avg(arr: [String])->Double {
    let arr = array.flatMap(Double.init)
    var avg = 0.0
    if arr.count > 0 {
        avg = arr.reduce(0.0, combine: + ) / Double(arr.count)
    }
    return avg
}

let a = avg(array)
print(a) // 20.6

2 Comments

That's great. Could you explain flatMap(Double.init)?
Why not like this? flatMap { Double($0) }

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.