Sam
Sam

Reputation: 11

Optional Int to Arrays in Swift - Average Function

How can I write an average function in swift in where input in an array of optional Ints? Here's what I wrote so far:

func ave(array: [Int?] -> Double?) {

    var mysum = 0
    for num in array {
        mysum += num
    }
    return Double(mysum)/Double(array.count)
}

I read a lot of Optional ints but I don't know how to implement that when the input in an array of optional ints... Any help?

Upvotes: 1

Views: 624

Answers (6)

When you have an array with optional elements, it usually helps to use flatmap to first give you an array with no optionals...

func ave ( nums:[Int?] ) -> Double?
{
    var answer : Double? = .None
    let realInts = nums.flatMap { $0 }

    if ( realInts.count > 0 ) {
        var accum : Int = 0
        realInts.map { accum += $0 }
        answer = Double(accum) / Double(realInts.count)
    }

    return answer
}

Upvotes: 1

maxpovver
maxpovver

Reputation: 1600

One more option:

func ave(array: [Int?])-> Double {

    var mysum = 0
    var c = 0
    for num in array {
        if let n = num {
           mysum += n
           c++
    }
    return Double(mysum)/Double(c)
}

Upvotes: 0

justinpawela
justinpawela

Reputation: 1978

Here it is in Swift 2, since it is only a few days away now:

func ave(array: [Int?]) -> Double? {
    guard array.filter({ $0 == nil }).isEmpty else {
        print("One of the Ints was nil")
        return nil
    }
    return Double(array.reduce(0, { $0 + $1! })) / Double(array.count)
}

The opening guard statement checks array for any nil members, and returns nil after printing a message if it finds any.

If no nil is found, we use a simple reduce statement to calculate the sum of the array members, then divide by the count.

Here are some examples of the results:

ave([1,2,3])      // 2
ave([1,2,nil])    // nil (and the message will print)
ave([])           // Double.NaN (because you're dividing by zero)

If you want it in Swift 1.2, the implementation is not all that different:

func ave(array: [Int?]) -> Double? {
    if array.filter({ $0 == nil }).isEmpty {
        return Double(array.reduce(0, combine: { $0 + $1! })) / Double(array.count)
    } else {
        print("One of the Ints was nil")
        return nil
    }
}

Upvotes: 5

pacification
pacification

Reputation: 6018

In Swift you can do average func in two lines (you can do this in one line, of course, but then you get duplicate code - array.filter { $0 != nil }):

func average(array: [Int?]) -> Double {
    let arrayWhithoutNils = array.filter { $0 != nil }
    return arrayWhithoutNils.count > 0 ? (arrayWhithoutNils.map { Double($0!) }.reduce(0, combine: +) / Double(arrayWhithoutNils.count)) : 0
}

print(average([1, 2, 3])) // 2
print(average([nil, 4, 5, nil])) // 4.5

Upvotes: 1

Luca Angeletti
Luca Angeletti

Reputation: 59526

This should do the job

func average(numbers: [Int?]) -> Double {
    let sum = numbers.reduce(0) { $0 + ($1 ?? 0) }
    let numValidElms = numbers.filter { $0 != nil }.count

    let delta = numbers.count - numValidElms
    if delta > 0 {
        println("Found \(delta) nil values")
    }

    if numValidElms > 0 {
        return Double(sum) / Double(numValidElms)
    } else {
        return 0
    }
}

Examples

average([nil]) // 0
average([1,2,3]) // 2
average([1, nil, 2]) // 1.5

Hope this helps.

Upvotes: 0

Christian
Christian

Reputation: 22343

You just need to make an if let check in your for loop.

func ave(array: [Int?])-> Double {
    var arraySize = array.count
    var mysum = 0
    for num in array {
        if let num = num{
            mysum += num
        }else{
            arraySize--
            println("Is nil")
        }
    }
    return Double(mysum)/Double(arraySize)
}

As you maybe see, I've added a variable called arraySize because you need to check what's the size of your real array. Without the nils. Otherwise your final calculation doesn't work as wanted. Also I've changed your func-header a little bit. There was a mistake in your code before:

func ave(array: [Int?] -> Double?) {
                       ^^^^^^^^^^

The return-value has to be outside of the ():

func ave(array: [Int?])-> Double {

Upvotes: 1

Related Questions