Reputation: 11
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
Reputation: 75058
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
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
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
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
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
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