Unclear Swift coding - swift

var occurences: [Int : Int] = [:]
for number in numbers {
if var value = occurences[number] {
occurences[number] = ++value
} else {
occurences[number] = 1
}
}
I understand the first 2 lines that it declares an empty dictionary and I have an array of numbers to iterate in a for-in loop, but can someone explain the 4th and 5th line, please. I just don't get how it declares which one is the key and which one is the value. Thank you so much, stucking here for like 2 days.

This line
if var value = occurences[number]
means that it checks to see if occurences has some value stored for key number and then in next line
occurences[number] = ++value
it increments the value by using ++ and then saves that to the occurences dict.

Related

Loop through a range of an Array [duplicate]

This question already has answers here:
How to loop through an array from the second element in elegant way using Swift
(5 answers)
Closed 3 years ago.
How can I loop through an array range? Example if I had 5 objects in an array. I want to loop from index [3] to end of the array in this example it would go through and update objects 3-5 and skip objects 1 & 2. This is what I have so far using the stride method(this code isn't working). Is this the correct method? How can I achieve this?
stride(from: markers[index], to: markers.endIndex, by: 1).forEach { i in
// Do something for each array object
}
You can use the range operator to get sequences of indices or slices of the array. Which you use depends on what you are trying to do. For clarity I am going to leave out error checking.
For example:
let letters = ["a", "b", "c", "d", "e"]
letters[3...].forEach { print($0) } // prints d e
// or you can print up to index 3
letters[...3].forEach { print($0) } // prints a b c d
// or print elements 1-3 inclusive
letters[1...3].forEach { print($0) } // prints b c d
// or print elements 1-3 excluding index 3
letters[1..<3].forEach { print($0) } // prints b c d
If you wanted to modify the elements of the array you pass in the indices rather than the elements
var mutableLetters = ["a","b","c","d","e"]
(3..<mutableLetters.count).forEach {
mutableLetters[$0] = mutableLetters[$0].uppercased()
}
notice here we need to specify both limits because the range knows nothing about the array.
It's often more Swifty not to modify things in place so, if this fits your use case you might consider something like this:
let immutableLetters = ["a","b","c","d","e"]
let upperCasedFromThreeOn = immutableLetters[3...].map { $0.uppercased() }
// upperCasedFromThreeOn = ["D","E"]
As a final note, sometimes you need to know both the index and the element. You can use a forEach on the indices as above, but another way is to use enumerated() this creates a tuple of the index and element.
let range = 2...4
immutableLetters.enumerated()
.filter { (index,_) in range.contains(index) }
.forEach { (index, element) in
print("\(index) \(element)")
}
Here I've used a filter after the enumeration so that the indices match the original array.
You can simply iterate over your array slice dropping the first n elements:
let markers = ["a","b","c","d","e"]
for marker in markers.dropFirst(2) {
print(marker) // this will print 'c d e'
}
If you need to change your array you can iterate over a slice of its indices:
let markers = ["a","b","c","d","e"]
for index in markers.indices.dropFirst(2) {
print(markers[index])
}
You can simply loop through the array using Range Operator in Swift like,
var markers = ["M1","M2","M3","M4","M5"]
let count = markers.count
if count > 2 {
for i in 2..<count {
//add your code here..
}
}
In the above code, I've used half-open range operator(..<)

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.

Left side of mutating operator isn't mutable: 'gpa' is a 'let' constant

I am currently struggling with an error for a homework assignment in my coding class. We are creating a loop that loops through an array of gpa values and then adds it to a variable named totalGradePoints. The problem is that I am coming across an error when the loop runs:
Left side of mutating operator isn't mutable: 'gpa' is a 'let' constant
The error is on this line:
var totalGradePoints = Double()
for gpa in gpaValues {
let averageGPA: Double = gpa += totalGradePoints
}
Here is my full code:
//: Playground - noun: a place where people can play
import UIKit
// You are the university registrar processing a transfer student's transcripts that contains grades that are a mix of letters and numbers. You need to add them to our system, but first you need to convert the letters into grade points.
// Here's an array of the student's grades.
var transferGrades: [Any] = ["C", 95.2, 85, "D", "A", 93.23, "P", 90, 100]
// To prepare for converting the letters to numerical grades, create a function that returns a double, inside which you create a switch that will convert an A to a 95, B to 85, C to 75, D to 65, , P (for passing) to 75. Everything else will be a zero.
func gradeConverter(letterGrade: String) -> Double {
switch letterGrade {
case "A":
return 95
case "B":
return 85
case "C":
return 75
case "D":
return 65
case "P":
return 75
default: // Is this where everything else is zero?
return 0
}
}
// Create a new array called convertedGrades that stores doubles.
var convertedGrades: [Double] = [98.75, 75.5, 60.0, 100.0, 82.25, 87.5]
// Loop through the transferGrades array, inspecing each item for type and sending strings (your letter grades) to the function you just made and storing the returned double in your convertedGrades array. If your loop encounters a double, you can place it directly into the new array without converting it. It it encounters an int, you will need to convert it to a double before storing it. Print the array. (You may notice that some of your doulbes are stored with many zeros in the decimal places. It's not an error, so you can ignore that for now)
for grade in transferGrades {
if let gradeAsString = grade as? String {
gradeConverter(letterGrade: gradeAsString)
} else if let gradeAsDouble = grade as? Double {
transferGrades.append(gradeAsDouble)
} else if let gradeAsInt = grade as? Int {
Double(gradeAsInt)
transferGrades.append(gradeAsInt)
}
}
print(transferGrades)
// Now that we have an array of numerical grades, we need to calculate the student's GPA. Create a new array called GPAValues that stores doubles.
var gpaValues: [Double] = [2.5, 3.0, 4.0, 3.12, 2.97, 2.27]
// Like with the letter conversion function and switch you created before, make a new function called calculateGPA that takes a double and returns a double. Inside your function, create another switch that does the following conversion. Grades below 60 earn zero grade points, grades in the 60s earn 1, 70s earn 2, 80s earn 3, and 90s and above earn 4.
func calculateGPA(gpaValue: Double) -> Double {
switch gpaValue {
case 0..<59:
return 0
case 60...69:
return 1
case 70...79:
return 2
case 80...89:
return 3
case 90..<100:
return 4
default:
return 0
}
}
// Loop through your convertedGrades array and append the grade point value to the GPAValues array. Because your calculateGPA function returns a value, you can use it just like a varialbe, so rather than calculate the grade points and then put that varialbe in your append statement, append the actual function. i.e. myArray.append(myFunction(rawValueToBeConverted))
for gpa in gpaValues {
gpaValues.append(calculateGPA(gpaValue: gpa))
}
// Finally, calculate the average GPA by looping through the GPA and using the += operator to add it to a variable called totalGradePoints. You may need to initialize the variable before using it in the loop. i.e. var initialized = Double()
var totalGradePoints = Double()
for gpa in gpaValues {
let averageGPA: Double = gpa += totalGradePoints
}
// Count the number of elements in the array (by using the count method, not your fingers) and store that number in a variable called numberOfGrades. Pay attention to creating your variables with the right types. Swift will tell you if you're doing it wrong.
var numberOfGrades: Int = gpaValues.count
// Divide the totalGradePoints by numberOfGrades to store in a variable called transferGPA.
var transferGPA: Double = Double(totalGradePoints) / Double(numberOfGrades)
// Using code, add one numerical grade and one letter grade to the transferGrades array that we started with (i.e. append the values rather than manualy writing them into the line at the beginning of this file) and check that your transferGPA value updates. You'll need to append the new grades on the line below the existing transferGrades array so that your changes ripple through the playground.
transferGrades.append(97.56)
transferGrades.append("B")
averageGPA must be define using the var keyword to make it mutable later on when summing up the values.
var averageGPA: Double = 0
for gpa in gpaValues {
averageGPA += gpa
}
averageGPA = averageGPA / Double(gpaValues.count)
Recall the average is calculated by summing up the score and dividing the number of scores.
Defining something with let means that the following will be a constant.
let answer: Int = 42
answer = 43 /* Illegal operation. Cannot mutate a constant */
Left side of mutating operator isn't mutable: 'gpa' is a 'let' constant
The problem is that gpa is a constant, you can't modify its value. And the "+=" operator means "increase gpa's value by totalGradePoints", it is trying to increase the value of gpa. What you probably mean to do is make averageGPA equal the sum of gpa and totalGradePoints. For that you would do this:
let averageGPA: Double = gpa + totalGradePoints

cannot invoke avgArray with an argument list of int

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)

Fatal Error: Array Index out of range in Swift Xcode6

I keep getting this error in my func
I'm trying to read the value in array answerRecord. I uses a global var arrayCount, which keep track which index im currently pointing to.
func buttonColourControl(){
switch answerRecord[arrayCount]{
case1: xxxxxxx
I did a println in my earlier func and it return a value of int 1 for the var arrayCount
Therefore arrayCount is not empty. So it should be able to interpret the array as:
*assuming arrayCount is now 1
answerRecord[arrayCount] should be interpreted as answerRecord[1]
Please correct me if im wrong
#IBAction func nextButtonClicked(sender: UIButton) {
arrayCount = ++arrayCount
question.text = spouseQuesion[arrayCount]
controlBackNextButton()
answer1Label.text = spouseAnswer1[arrayCount]
answer2Label.text = spouseAnswer2[arrayCount]
answer3Label.text = spouseAnswer3[arrayCount]
println(arrayCount)
buttonColourControl()
}
Let's say you have an array with one object in it:
let arr = ["hello"]
The only valid index into that array is 0. arr[0] is legal. arr[1] is not. The array has 1 element but its index number is 0.
This is true for any array. Every array holds some number of elements. It might be 0 elements, in which case no index is legal. It might be 3 elements, in which case you can refer to the array's elements by index numbers 0, 1, and 2. And so on. That's all. Those are the rules. You cannot use any other index number or you will crash.
So the error message is simply telling you that you are making that mistake. You have an array answerRecord and it has some number of elements - I have no idea how many, and it doesn't matter. Then you are using the expression answerRecord[arrayCount] and the value of arrayCount is outside the bounds I have just explained. That's all you need to know. The error message tells you the bug in your program. Now you can fix it.