cannot invoke avgArray with an argument list of int - swift

I'm new to Swift, and just start to learn this language by following The Swift Programming Language. In this book, there is an exercise question that ask me to write a function to calculate the average of an array. Here is my code:
func avgArray(elements: Int...)->Double{
var avg:Double = 0
var sum = 0
var count = 0
for element in elements {
sum += element
count += 1
}
avg = Double(sum) / Double(count)
return avg
}
let numberlist = [2,3,6,7,2,7,0,9,12]
let average = avgArray(numberlist)
I don't know why I can't pass the array into my function. Also, is there a way besides using a count variable to keep track of the number of elements in the array?

I don't know why I can't pass the array into my function.
Your elements is not an array, it is a variadic parameter. Change it to
func avgArray(elements: [Int])->Double{
and you should be good to go.
is there a way besides using a count variable to keep track of the
number of elements in the array?
Absolutely. count property of the array itself. You can use it in your code like this:
avg = Double(sum) / Double(elements.count)

Related

I seem to have an infinite while loop in my Swift code and I can't figure out why

var array: [Int] = []
//Here I make an array to try to dictate when to perform an IBaction.
func random() -> Int {
let rand = arc4random_uniform(52)*10+10
return Int(rand)
}
//this function makes a random integer for me
func finalRand() -> Int {
var num = random()
while (array.contains(num) == true){
if (num == 520){
num = 10
}else {
num += 10
}
}
array.append(num)
return num
}
The logic in the while statement is somewhat confusing, but you could try this:
var array:Array<Int> = []
func finalRand() -> Int {
var num = Int(arc4random_uniform(52)*10+10)
while array.contains(num) {
num = Int(arc4random_uniform(52)*10+10)
}
array.append(num)
return num
}
This way there will never be a repeat, and you have less boiler code.
There is probably a better method involving Sets, but I'm sorry I do not know much about that.
A few things:
Once your array has all 52 values, an attempt to add the 53rd number will end up in an infinite loop because all 52 values are already in your array.
In contemporary Swift versions, you can simplify your random routine to
func random() -> Int {
return Int.random(in: 1...52) * 10
}
It seems like you might want a shuffled array of your 52 different values, which you can reduce to:
let array = Array(1...52).map { $0 * 10 }
.shuffled()
Just iterate through that shuffled array of values.
If you really need to continue generating numbers when you’re done going through all of the values, you could, for example, reshuffle the array and start from the beginning of the newly shuffled array.
As an aside, your routine will not generate truly random sequence. For example, let’s imagine that your code just happened to populate the values 10 through 500, with only 510 and 520 being the final possible remaining values: Your routine is 51 times as likely to generate 510 over 520 for the next value. You want to do a Fisher-Yates shuffle, like the built-in shuffled routine does, to generate a truly evenly distributed series of values. Just generate array of possible values and shuffle it.

Swift store all numbers that are random generated and won't generated them again

I am trying to store all numbers that the random number generator generate. After that the number generator needs to check if the number already was generated and if so it will keep generate a new number until all number for example 1 to 30 are generated. I have so far only the random number generator:
if let Aantalvragen = snapshot?.data()!["Aantal vragen"] as? String {
self.AantalVragenDef = Aantalvragen
}
let RandomVraag = Int(arc4random_uniform(UInt32(self.AantalVragenDef)!) + 1)
AantalVragenDef is an number that indicates how many questions there are. So the generator knows how far it can generate. Please help.
The easiest is probably to create an array or list and fill it with the numbers 1 to n that you want, shuffle it and then use the numbers in the order they appear. That way you are guaranteed that each number show up exactly once.
See how to shuffle an array in Swift
I believe what you are trying to get is a random generator that generates numbers from 1 to the number of questions, but if the number already exists, you don't want to keep it. I suggest using if-else statements and arrays.
The code might look something like this:
if let Aantalvragen = snapshot?.data()!["Aantal vragen"] as? String {
self.AantalVragenDef = Aantalvragen
}
var array = [Int]()
while array.count != self.AantalVragenDef {
let RandomVraag = Int(arc4random_uniform(UInt32(self.AantalVragenDef)!) + 1)
if array.contains(RandomVraag) == false {
array.append(RandomVraag)
}
}
This loop will continue until there are (number of questions) integers in the array. Let me know if this is what you are looking for.
Good Luck, Arnav

Can this be more Swift3-like?

What I want to do is populate an Array (sequence) by appending in the elements of another Array (availableExercises), one by one. I want to do it one by one because the sequence has to hold a given number of items. The available exercises list is in nature finite, and I want to use its elements as many times as I want, as opposed to a multiple number of the available list total.
The current code included does exactly that and works. It is possible to just paste that in a Playground to see it at work.
My question is: Is there a better Swift3 way to achieve the same result? Although the code works, I'd like to not need the variable i. Swift3 allows for structured code like closures and I'm failing to see how I could use them better. It seems to me there would be a better structure for this which is just out of reach at the moment.
Here's the code:
import UIKit
let repTime = 20 //seconds
let restTime = 10 //seconds
let woDuration = 3 //minutes
let totalWOTime = woDuration * 60
let sessionTime = repTime + restTime
let totalSessions = totalWOTime / sessionTime
let availableExercises = ["push up","deep squat","burpee","HHSA plank"]
var sequence = [String]()
var i = 0
while sequence.count < totalSessions {
if i < availableExercises.count {
sequence.append(availableExercises[i])
i += 1
}
else { i = 0 }
}
sequence
You can overcome from i using modulo of sequence.count % availableExercises.count like this way.
var sequence = [String]()
while(sequence.count < totalSessions) {
let currentIndex = sequence.count % availableExercises.count
sequence.append(availableExercises[currentIndex])
}
print(sequence)
//["push up", "deep squat", "burpee", "HHSA plank", "push up", "deep squat"]
You can condense your logic by using map(_:) and the remainder operator %:
let sequence = (0..<totalSessions).map {
availableExercises[$0 % availableExercises.count]
}
map(_:) will iterate from 0 up to (but not including) totalSessions, and for each index, the corresponding element in availableExercises will be used in the result, with the remainder operator allowing you to 'wrap around' once you reach the end of availableExercises.
This also has the advantage of preallocating the resultant array (which map(_:) will do for you), preventing it from being needlessly re-allocated upon appending.
Personally, Nirav's solution is probably the best, but I can't help offering this solution, particularly because it demonstrates (pseudo-)infinite lazy sequences in Swift:
Array(
repeatElement(availableExercises, count: .max)
.joined()
.prefix(totalSessions))
If you just want to iterate over this, you of course don't need the Array(), you can leave the whole thing lazy. Wrapping it up in Array() just forces it to evaluate immediately ("strictly") and avoids the crazy BidirectionalSlice<FlattenBidirectionalCollection<Repeated<Array<String>>>> type.

How to compare random numbers in Swift

I’m a beginner in programming and playing around with the arc4random_uniform() function in Swift. The program I’m making so far generates a random number from 1-10 regenerated by a UIButton. However, I want the variable ’highest' that gets initialised to the random number to update if the next generated number is larger than the one currently held in it. For example the random number is 6 which is stored in highest and if the next number is 8 highest becomes 8. I don't know how to go about this. I have connected the UIButton to an IBAction function and have the following code:
var randomValue = arc4random_uniform(11) + 1
highest = Int(randomValue)
if (Int(randomValue) < highest) {
// Don’t know what to do
}
Initialise highest to 0
Every time you generate a new random number, replace the value of highest with the higher of the two numbers
highest = max(highest, randomValue)
The max() function is part of the Swift standard library and returns the larger of the two passed in vales.
edited to add
Here's a playground showing this with a bit more detail, including casting of types:
var highest: Int = 0
func random() -> Int {
let r = arc4random_uniform(10) + 1
return Int(r)
}
var randomValue = random()
highest = max(highest, randomValue)
You can see that multiple calls persist the highest value.

swift programming language tuple

I'm relatively new to the programming scene (my only experience was C++ in first year engineering) and I'm trying to teach myself Swift language. I have the Swift Programming Language e-book from the App Store and came across the Function and Closure section regarding Tuples and am currently confused. The code they provide as an example is:
func calculateStatistics(scores:[Int]) -> (min:Int, max:Int, sum:Int) {
var min = scores[0]
var max = scores[0]
var sum = 0
for score in scores {
if score > max {
max = score
} else if score < min {
min = score
}
sum += score
}
return (min, max, sum)
}
let calculateStatistics([5, 3, 100, 3, 9])
and it'll output (3, 100, 120).
I'm just not sure about the process of how they get those values via the For-Loop and if-statement.
If any one of you can kindly walk me through whats exactly is happening in this if-statement that would be greatly appreciated!! My thinking is obviously wrong but the way I viewed it was that the min and max value is "5" by the initial variable declaration. But what is the initial value of "score" and how do you determine if score is > or < the max and min?
Tuples are just a group of values. The function is declared to return a tuple of three ints. At the end of the function there's a return statements where the resulting tuple is created from existing variables.
As for the loops and ifs, they just go through the list given as the parameter to the function, and find the highest and lowest values in the list, like this:
max is initialized to be the first value in the list. (It has to have an initial values so that it can be compared against other values with < and >.)
Go through every int in the list with for score in scores (score is initialized to be the next value in the list with each iteration: first it's 5, then 3, then 100, etc.).
If an int is found to be greater than max, max is updated to that value.
After going through every int in the list, max will have the value of the greatest int in that list.
And same for min.
Edit: In the Swift Programming Language e-book, a few pages before Functions and Closures, there's an explanation on the for-in loop structure. Check it out.