Populate a multidimensional array with a loop [duplicate] - swift

This question already has answers here:
Error: "array index out of range" in multidimensional array
(2 answers)
Closed 6 years ago.
I'm trying to populate a multidimensional array with this code:
var array = [[Int]]()
for i in 0...3 {
for j in 0...3{
array[i][j] = i + j <<- Error
}
}
But I get an error:
fatal error: Index out of range
What am I doing wrong?

[[Int]] is not a multidimensional array. It is an array of arrays. That's a very different thing. For example, in an array of arrays, each row may have a different number of columns. It's generally a bad idea to use a nested array as a multidimensional array, particularly a mutable one. It's often incredibly inefficient to modify because it causes a lot of copying every time you change it.
Swift doesn't have a multidimensional array type. If you really need one, you generally have to build it yourself, or redesign to avoid it. If it's small enough, and doesn't change much, it's not that big a deal, but don't let them get large.
That said, the problem is that element [0][0] doesn't exist because you didn't create it. You'd need to initialize the array this way before using it:
var array = Array(repeating: Array(repeating: 0, count: 4), count: 4)
This creates an array of 4 arrays of 4 zeros.
If you want specifically the layout you describe, possibly a better approach is mapping, which is likely going to be more efficient (since it doesn't keep modifying the nested array):
let array = (0...3).map { i in
(0...3).map { j in
return i + j
}
}

Calling array[i][j] is for elements that are already there. You cannot use it to initialize the array, because currently it is just an empty array. You should be using .append instead. Keep in mind that this actually isn't a multi-dimensional array like Rob Napier states, but it accomplishes the same goal in this scenario. Try something like this:
var array = [[Int]]()
for i in 0...3 {
var subArray = [Int]()
for j in 0...3 {
subArray.append(i + j)
}
array.append(subArray)
}
This prints:
[[0, 1, 2, 3], [1, 2, 3, 4], [2, 3, 4, 5], [3, 4, 5, 6]]
Again, may not be the best approach, but this is just how you could do it in Swift.

Related

Array with multiple values per index?

I'm learning swift, and I do the sololearn course to get some knowledge, but I bumped into something that I don't understand.
It is about modifying an array's values. The questionable part states the following:
In the following example, the elements with index 1, 2, 3 are replaced with two new values.
shoppingList[1...3] = [“Bananas”, “Oranges”]
How can an one dimensional array take more than one value per index? And how do I access them? Am I misunderstanding something?
What this code does is replacing the element of shoppingList in the 1...3 range using Array.subscript(_:)
That means considering this array:
var shoppingList = ["Apples", "Strawberries", "Pears", "Pineaples"]
that with:
shoppingList[1...3] = ["Bananas", "Oranges"]
Strawberries, Pears and Pineaples will be replaced by Bananas and Oranges.
so the resulting array will be: Apples, Bananas, Oranges
When you assign to a range of indices in an array (array[1...3]), those elements are removed from the array and the new elements are 'slotted in' in their place. This can result in the array growing or shrinking.
var array = Array(0...5)
// [0, 1, 2, 3, 4, 5]
array[1...3] = [-1, -2]
// [0, -1, -2, 3, 4]
Notice how our array's length is now one element shorter.
You could use a tuple (Value, Value), or create a struct to handle your values there, in fact if you plan to reuse this pair or value, a struct is the way to go.
By the way, there's no need to add [1..3], just put the values inside the brackets.
struct Value {
var name: String
var lastName: String
}
let values = [Value(name: "Mary", lastName: "Queen"), Value(name: "John", lastName: "Black")]
// Access to properties
let lastName = values[1].lastName
// OR
let tuples = [("Mary", "Queen"), ("John", "Black")]
let lastNameTuple = tuples[1].1
Hope you're enjoying Swift!

How to create an array by multiplying another array in a functional way? [duplicate]

This question already has answers here:
Repeating array in Swift
(4 answers)
Closed 5 years ago.
I'd like to create an array that contains elements from another array multiplied by some Int value.
Example:
the following code
let arr = [1,2,3]
let multiplier = 3
print(function(arr, multiplier))
should return
[1,2,3,1,2,3,1,2,3]
I know how to make it using nested for loops, but I'm looking for some nifty functional way. I was thinking about map() function, but it iterates over each element of a given array, which is not my use case I suppose.
Main idea:
Create array of arrays,
flatMap to one-dimensional array.
Example:
let arr = [1, 2, 3]
let multiplayer = 3
print(Array(repeating: arr, count: multiplayer).flatMap({ $0 }))

Index out of range in Swift with removeAtIndex

I tried to remove an element in NSUserDefaults which is the same as stockSymbol's value when click a button. My idea is that cast the NSUserDefaults to an array and remove the element with removeAtIndex. Here is my code.
#IBAction func buttonFilledStarClicked(sender: AnyObject) {
NSLog("Filled star clicked")
self.buttonFilledStar.hidden = true
self.buttonEmptyStar.hidden = false
var Array = NSUserDefaults.standardUserDefaults().objectForKey("favorites")! as! [String]
var countArray = (NSUserDefaults.standardUserDefaults().objectForKey("favorites")! as! [String]).count - 1
for i in 0...countArray {
if stockSymbol! == Array[i] {
NSLog("i is : \(i)")
Array.removeAtIndex(i)
}
else {}
}
NSLog("Array is: \(Array), countArray is: \(countArray)")
}
However it has 'out of index' error.
It works when I just comment Array.removeAtIndex(i) out.
Array looks like this --
["aa", "bb", "Test!", "Test!"]
Any suggestions? Thank you in advance.
So, the change you can make to resolve the error with the least impact on your code overall would be to simply iterate through the indices backwards:
for i in (0...countArray).reverse() {
if stockSymbol! == Array[i] {
NSLog("i is : \(i)")
Array.removeAtIndex(i)
}
else {}
}
But the best option is to just use Swift's filter:
Array = Array.filter { $0 != stockSymbol }
An expanded note on why the crash is happening...
Let's take a simplified example. Say I have the following array:
var arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
And I want to remove all of the odd numbers out of it. Using your first naïve approach, I might write my logic like this:
for i in 0..<arr.count {
if arr[i] % 2 != 0 {
arr.removeAtIndex(i)
}
}
Look at what happens on each iteration.
On the first iteration, we have arr[i] of 1. This is an odd number, so we'll removeAtIndex, and our array now actually looks like this:
[2, 3, 4, 5, 6, 7, 8, 9, 10]
The array's size is now smaller--it has just 9 elements. But the loop doesn't work like an old C-style for loop where i < arr.count is checked on each iteration (which is part of why this loop is faster).
But notice something else that happens when we iterate forward...
On the second iteration, i is equal to 1, and so what does arr[i] give us? It gives us 3. We never even check 2. On the first iteration, when i was 0, it was at index 1. On the second iteration, when i is 1, the 2 is at index 0.
So on the second iteration, we'll call removeAtIndex with i equal to 1 and remove the 3.
This pattern will continue for a few iterations until we end up with our array of just even numbers:
[2, 4, 6, 8, 10]
But this happens after the iteration where i was equal to 4, and the loop is going to try running until i is equal to 10.
On the sixth iteration of the loop, we try to access the element at index 5 of the array. But the array only has five elements, so the largest index is 4. When we try to access index 5, we crash.
You should not remove it from inside of the loop, when you call removeAtIndex(i) Array removes the item so you have 1 less item then countArray.. so you have to have another array to remember which item you want to remove and remove it outside of the loop.. or better option is to use filter
// Filter only strings that match stockSymbol
Array = Array.filter { $0 == stockSymbol! }
Try to find out which i that give you index out of range result. Is it the 0 or the last one. Maybe you will find some other useful clue.
First of all Array is a type, maybe you can call:
var favourites = NSUserDefaults.standardUserDefaults().objectForKey("favorites")! as! [String]
Then you don't need a array's count variable you can access using count arrays property.
Finally if you are iterating through an array and remove an element it always going to throw "index's error" because the index is not the same as the beginning..
For solving this you can take two pointers of the index variable, but what I would do is something like this:
var correctElements = favourites.filter({$0!=stockSymbol})

How to create an array with incremented values in Swift? [duplicate]

This question already has answers here:
Is there a way to instantly generate an array filled with a range of values in Swift?
(4 answers)
Closed 7 years ago.
I know that I can create an array with repeated values in Swift with:
var myArray = [Int](count: 5, repeatedValue: 0)
But is there a way to create an array with incremented values such as [0, 1, 2, 3, 4] other than to do a loop such as
var myArray = [Int]()
for i in 0 ... 4 {
myArray.append(i)
}
I know that code is pretty straightforward, readable, and bulletproof, but it feels like I should be able pass some function in some way to the array as it's created to provided the incremented values. It might not be worth the cost in readability or computationally more efficient, but I'm curious nonetheless.
Use the ... notation / operator:
let arr1 = 0...4
That gets you a Range, which you can easily turn into a "regular" Array:
let arr2 = Array(0...4)

How to add integer to array (with explicite int index) in swift?

I read swift handbook and was trying to do some exercises. But I run into a problem and I do not know if I do something wrong or if xCode 6 beta is just buggy.
// Playground - noun: a place where people can play
import Cocoa
let interestingNumbers = [
"Prime": [2, 3, 5, 7, 11, 13],
"Fibonacci": [1, 1, 2, 3, 5, 8],
"Square": [1, 4, 9, 16, 25],
]
var largest = 0
var lastLargest = Integer[]()
var index = 0
for (kind, numbers) in interestingNumbers {
for number in numbers {
if number > largest {
//lastLargest[index] = number
index++
largest = number
}
}
}
index
lastLargest
largest
As soon as I uncomment lastLargest[index] = number I do not get any results on right side in playground. Nor I get any infos about index, lastLargest or largest.
Following example does not work either:
var index2 = 0
var lastLargest2 = Integer[]()
lastLargest2[index2] = 1
index2++
lastLargest2[index2] = 2
You are appending using an out of bound array-index. Don't do that. Instead, use append:
lastLargest.append(number)
From Apple's documentation:
You can’t use subscript syntax to append a new item to the end of an array. If you try to use subscript syntax to retrieve or set a value for an index that is outside of an array’s existing bounds, you will trigger a runtime error.
When you're using explicit indexes (subscript notation) to set values in a mutable array, some value must already exist in that array at that index. When you use subscript notation, you're essentially using a 'set', rather than a 'set and add if necessary'.
As a result, you should be using:
lastLargest.insert(number, atIndex: index)
If you want to insert a new item. This will let you insert an item at the specified index, assuming your collection's size is already greater than or equal to the index you're trying to replace.