Swift array basics - swift

Gives an Index out of range eror.
Is there a syntax error or logic ?
func generateGameBoard()->([Int]){
var gboard = [Int]();
var i : Int = 0;
for(i=0;i<8;i++){
gboard[i]=1;
}
return gboard;
}
}

Dont you notice error in your code. You create an empty array and then ask index for 0 ..< 8 which is invalid. You should really use count to iterate over the contents.
func generateGameBoard()->([Int]){
var gboard = [Int]();
for i in 0 ..< gboard.count {
gboard[i]=1;
}
return gboard;
}

var gboard = [Int](); // you are creating an empty array here.
you need to append value in array
like
gboard.append(1) instead of gboard[i]=1;
and c style for loop and ++ opeartor will not use in next versions of swift.

You should also get ready for swift 3 and update the for loop part. It won't compile as it stand now in swift 3. You have to change it to:
for i in 0..<8 {
}

Related

Minimum value from range of Array

I have a list of prices and want to find the minimum price EXCLUDING the first element (this is a subset of another problem on HackerRank).
My version is too slow and times out. I suspect this is due to my ArraySlice.
Here is my (working) code:
func calculateMins(prices: [Int]) {
for j in 1..<prices.count {
let lowestPreviousPrice = prices[1...j].min()!
print (lowestPreviousPrice)
}
}
calculateMins(prices: [4,8,2,4,3])
Is there a better performing version of this, perhaps one that does not use an ArraySlice?
Just use dropFirst() function.
var array = [1,8,2,4,3]
var array2 = array.dropFirst() // Returns a subsequence containing all but the first element of the sequence.
array2.min() // 2
Why not keep it simple
func calculateMins(prices: [Int]) {
var min = Int.max
for i in 1..<prices.count {
if prices[i] < min { min = prices[i] }
}
print(min)
}
You have few options to solve this issue.
//Default way
prices.dropFirst().min()
//Functional way
prices.dropFirst().reduce(Int.max, { min($0, $1) })
You could also use suffix, which is quite same as dropFirst that this version could crash if in case array is empty.
array.suffix(from: 1).min()

Swift rating system loop and assign

Trying to build a rating system in Swift and looking for a cleaner way to loop through each of the values.
private func calculateRating(user: String) throws -> String {
let query = try Rating.makeQuery().filter("user", user).all()
var fiveStars = [Int]()
var fourStars = [Int]()
var threeStars = [Int]()
var twoStars = [Int]()
var onestar = [Int]()
if query.count > 1 {
for rating in query {
// Check each value and assign it to its associated value
// insert large if/else condition here :)
}
// Perform calculation and return value below
return ""
} else {
// Only one rating has been set
return query[0].value
}
}
Currently I'm looping through each of the values and assigning the rating to it's associated array fiveStars fourStars etc. I will then calculate the rating by the standard multiplication method. Is there a cleaner way to loop through the ratings and assign it to the relevant fiveStars array etc without creating a long if/else conditional?
Thanks
Edit: Sample output would be a single rounded up value out of 5 i.e. "4" out of five based on 1000's of multiple ratings.
let twoStars: [Int] = query.filter {$0.val == 2} .map {$0.val}
And so on.

Is there a way to override the Copy on Write behavior for Swift arrays?

I'm working on a project where I need to work with large arrays, and by using UnsafeMutablePointers, I get a threefold speed increase over using the regular array methods. However, I believe the copy on write behavior is causing me to change instances that I do not want to be affected. For example, in the following code, I want to update the values in copyArray, but leave the original values in anArray.
import Foundation
func increaseWithPointers(_ arr: inout [Int]) {
let count = arr.count
let ptr = UnsafeMutablePointer(mutating: &arr)
for i in 0..<count {
ptr[i] = ptr[i] + 1
}
}
var anArray = [1,2,3,4,5]
var copyArray = anArray
increaseWithPointers(&copyArray)
print(anArray)
Executing this code prints [2,3,4,5,6].
I can get around this by declaring copyArray as follows:
var copyArray = [Int](repeating: 0, count: 5)
for i in 0..<5 {
copyArray[i] = anArray[i]
}
However, this requires writing each value twice: to zero, then to the intended value. Is there a way to efficiently guarantee a copy of an array?
I can reproduce your problem using Xcode 9 beta 3, but not using Xcode 8.3.3. I suggest you file a Swift bug report.
This fixes the problem:
import Foundation
func increaseWithPointers(_ arr: inout [Int]) {
arr.withUnsafeMutableBufferPointer { (buffer) in
for i in buffer.indices {
buffer[i] += 1
}
}
}
var anArray = [1,2,3,4,5]
var copyArray = anArray
increaseWithPointers(&copyArray)
print(anArray)

function containing 2 loops

Have a sorting function here and when I change the -- decrementer to -= 1 that gets rid of one error but I still get the syyntax error.
func iSortBort(myList: Array) -> Array {
var extract = myList
for firstIndex in 0..<extract.count {
let key = extract[firstIndex]
for var secondIndex = firstIndex; secondIndex > -1; secondIndex--1 {
In case of doubt, any C-style for, regardless of its position or nesting level, can be trivially changed to a while loop:
var secondIndex = firstIndex
while secondIndex > -1 {
defer { i -= 1 }
// loop body
}
though you might be able to get away with stride in your case. (I don't remember how to use it off my head though, especially not in Swift 3.)
stride is indeed the way to go. Also, it seems like you would benefit from using enumerate(). Try this:
for (firstIndex, key) in extract.enumerate() {
for secondIndex in firstIndex.stride(through: 0, by: -1) {
...
}
}
check this out: http://bjmiller.me/post/137624096422/on-c-style-for-loops-removed-from-swift-3
like for decrementing:
for secondIndex in (0...firstIndex).reverse() {
print("comparing \(key) and \(myList[secondIndex])")
if key < extract[secondIndex] {
extract.removeAtIndex(secondIndex + 1)
extract.insert(key, atIndex: secondIndex)
}
}
The correct answer is to just use the included Swift sort function. That's all your code does so why re-invent the wheel? (Poorly btw, your code compares each element to itself which is totally unnecessary, and it loads up extract and then moves the elements around in it when it would be better to just build up the array as you go along.)

SWIFT IF ELSE and Modulo

In Swift, I need to create a simple for-condition-increment loop with all the multiples of 3 from 3-100. So far I have:
var multiplesOfThree: [String] = []
for var counter = 0; counter < 30; ++counter {
multiplesOfThree.append("0")
if counter == 3 {
multiplesOfThree.append("3")
} else if counter == 6 {
multiplesOfThree.append("6")
} else if counter == 9 {
multiplesOfThree.append("9")
}
println("Adding \(multiplesOfThree[counter]) to the Array.")
}
I would like to replace all the if and else if statements with something like:
if (index %3 == 0)
but I’m not sure what the proper syntax would be? Also, if I have a single IF statement do I need a .append line to add to the Array?
You are very much on the right track. A few notes:
Swift provides a more concise way to iterate over a fixed number of integers using the ..< operator (an open range operator).
Your if statement with the modulus operator is exactly correct
To make a string from an Int you can use \(expression) inside a string. This is called String Interpolation
Here is the working code:
var multiplesOfThree: [String] = []
for test in 0..<100 {
if (test % 3 == 0) {
multiplesOfThree.append("\(test)")
}
}
However, there is no reason to iterate over every number. You can simply continue to add 3 until you reach your max:
var multiplesOfThree: [String] = []
var multiple = 0
while multiple < 100 {
multiplesOfThree.append("\(multiple)")
multiple += 3
}
As rickster pointed out in the comments, you can also do this in a more concise way using a Strided Range with the by method:
var multiplesOfThree: [String] = []
for multiple in stride(from: 0, to: 100, by: 3) {
multiplesOfThree.append("\(multiple)")
}
Getting even more advanced, you can use the map function to do this all in one line. The map method lets you apply a transform on every element in an array:
let multiplesOfThree = Array(map(stride(from: 0, to: 100, by: 3), { "\($0)" }))
Note: To understand this final code, you will need to understand the syntax around closures well.