Using array values to init new array elements - arrays

I've put together the following sample code:
let tings = [1, 2, 4, 5, 6, 8]
class Foo {
var number: Int
init(something: Int) {
self.number = something
}
}
var list: [Foo] = []
for num in tings {
var temp = Foo(something: tings[num]) //excbadinstruction invop
list.append(Foo(something: 3)) //no error
list.append(Foo(something: Int(4))) //no error
list.append(Foo(something: tings[num])) //excbadinstruction invop
list.append(Foo(something: Int(tings[num]))) //excbadinstruction invop
}
I dont get what the problem is with the last two lines as in my opinion things[num] also is of type Int, and same of course with the last row.
If I specify the type of things to be [Int], nothing changes (which isnt strange to me)
I also have to explicitly state 'something:' which I didn't expect because it was the first and only argument of the initializer.
I hope anyone can explain this to me and/or give the right way to do this.

Swift Playground is fun and all, but it's pretty terrible when it comes to debugging.
If we duplicate this code in an actual compilable and build able application, we get no build time warnings or errors. However, as soon as we hit play and run the code, the problem is obvious. The console prints:
fatal error: Array index out of bounds
Here's the problem... our array has six elements. That means the maximum accessible index is 5.
Look at our loop:
for num in tings {
// do stuff
}
If we change the loop to print num, like this:
for num in tings {
println(num)
}
You'll see that it prints our tings array:
1
2
4
5
6
8
Now let's access the the element at each index:
for num in tings {
println(tings[num])
}
What prints?
2
4
6
8
fatal error: Array index out of range
What happened?
We tried to access the 6th index, because the fifth iteration of the loop, the fifth element of the array, is the Int 6. We're trying to access the 6th element, which is out of bounds for our array.
If you're trying to iterate of the elements of tings and instantiate a Foo for each element, you simply need this:
for num in tings {
list.append(Foo(something: num))
}
Or as Paul points out in a comment, if you need the index, you can iterate through the loop as such:
for (index, value) in enumerate(tings) {
// do stuff
}

Related

Index out of range (fatal error) when summing diagonals in square arrays

I need difference between first and second diagonal in square matrix array
func diagonalDifference(arr: [[Int]]) -> Int {
var sumFirstDiag = 0
for i in 0...arr.count-1 {
sumFirstDiag = sumFirstDiag + Int(arr[i][i])
}
var sumSecondDiag = 0
for y in 0...arr.count-1 {
sumSecondDiag = sumSecondDiag + Int(arr[y][arr.count - y])
}
print(abs(sumFirstDiag - sumSecondDiag))
return abs(sumFirstDiag - sumSecondDiag)
}
let array = [
[1,2,3,11],
[4,5,6,12],
[7,8,9,90],
[1,3,5,7]]
diagonalDifference(arr: array)
Error message:
Fatal error: Index out of range: file Swift/ContiguousArrayBuffer.swift, line 444
I figured I'd share a more functional approach to this same problem:
// The sum of elements along the diagonal from top-left to bottom-right
func diagonal1Sum(_ input: [[Int]]) -> Int {
input.indices
.map { input[$0][$0] }
.reduce(0, +) // I wish Swift had a built-in `.sum` :(
}
// The sum of elements along the diagonal from top-right to bottom-left
func diagonal2Sum(_ input: [[Int]]) -> Int {
zip(input.indices, input.indices.reversed())
.map { input[$0][$1] }
.reduce(0, +)
}
// The absolute value of the difference in sums of the two diagonals.
func diagonalDifference(_ input: [[Int]]) -> Int {
abs(diagonal1Sum(input) - diagonal2Sum(input))
}
let array = [
[1,2,3,11],
[4,5,6,12],
[7,8,9,90],
[1,3,5,7],
]
print(diagonalDifference(array))
There's a few things to notice:
0...arr.count-1 should be just expressed as arr.indices. The first form crashes on empty arrays. See https://github.com/amomchilov/Blog/blob/master/Proper%20Array%20Iteration.md
arr[i][i] is already an Int, there's no need to convert that into an Int.
sumSecondDiag = sumSecondDiag + something is more simply written as just sumSecondDiag += something
Meaningless parameter names like arr shouldn't be keyword labels. Compare diagonalDifference(arr: array) and diagonalDifference(array). The arr: in the first form doesn't really give you any information you didn't already have. You should omit that keyword label using a _.
You should not print the result out of a function that computes a result like this. Return the result, then print it. This gives users of your function the ability to choose whether they want to print, or not.
And most importantly: you can iterate through arr.indices.reversed() to get a sequence of indices that go from high to low, allowing you to access the row elements from top right to bottom left.
This is the key to avoiding the bug you encountered. You forgot the crucial - 1, which is why you were accessing the index out of bounds and causing the crash. If you just use the reversed reverse the array first, then access the nth element, you'll get back the n-th last value, without needing to remember to do acc.count - n - 1.
To pick the row, you still need the regular "forward indices", like array.indices().
You can use zip(_:_:) to iterate both of them at the same time, using the "forward index" to select the row, and the "backward index" to select a particular number from that row.
Thanks to #Rob for this suggestion.
Update notes
I revamped my recommendation. I was previously suggesting to use input[$0].reversed()[$0] under the misunderstanding that the result of reversed would be a view onto the array that would just perform constant-time index arithmetic. This is not the case. Each of these reversed calls was doing a full linear reversal of the array.

Check numbers divisible by 2 and print them in Kotlin

I am working on a task as part of my Kotlin course and I've been really stuck on this. I feel like it's something simple but I can't see it. Here is the explanation of what to do for this task:
You are given a List of integers. Iterate through the given List and print in a single line the elements that are divisible by 2.
Sample Input:
8 11 13 2
Sample Output:
8 2
This is my code (I have printed the numbers list to see what numbers I was being provided with, as I am not choosing them, they are given by the course automatically without me seeing them):
fun solution(numbers: List<Int>) {
var divisible = intArrayOf()
for (i in 0..numbers.lastIndex) {
if (numbers[i] % 2 == 0){
divisible = intArrayOf(numbers[i])
}
}
println("$numbers")
println("${divisible.joinToString("")}")
This was my output:
[8, 11, 13, 2]
2
I think I have done the part of checking if the numbers are divisible by 2 correctly, but I don't fully understand why it only prints 2, and why not 8 first if it divisible by 2. At first I was using a list instead of an array for the divisible variable, so I thought that might have been it, as lists are immutable if I'm not wrong, but it looks like that wasn't it. If anyone could explain to me what I'm doing wrong, I would really appreciate it!
You can use filter with predicate
Example :
val list = listOf(8,2,11,15)
the solution is so simple with kotlin
val result = list.filter { it % 2 == 0 }
You rewrite result holder (divisible = intArrayOf()) on each item that is divisible by 2, that's why only last match is stored in divisible array.
Instead of
divisible = intArrayOf(numbers[i])
you should write
divisible.add(numbers[i]) // no need to re-initialize
UPDATE: I've missed that array has no add operation. If it's suitable you can use list instead of array in order to have add operation available:
var divisible = mutableListOf<Int>()
P.S. There is a shorter way to do that with Kotlin:
fun solution(numbers: List<Int>) {
val divisible = numbers.filter { it % 2 == 0 }
println("$numbers")
println("${divisible.joinToString(" ")}")
}

Is it safe to iterate an array while modifying it?

I know you shouldn't, I kind of know why. But I mean I don't understand my own code once I am trying really to think what's going on.
So I have an array with bunch of objects. I am iterating over it and once I find an object with specific type, I remove it from the array, and add another object into the array. So something like this:
var arr = parent.allchildren() //getting all the children in array
for ele in arr{
if(ele==somethingHere){
parent.remove(ele)
parent.add(new ele) //add new child into child array
}
}
If I have an array of 1,2,3,4,5, and I remove 3 and add a 6 while iterating, the actual array would be 1,2,4,5,6 but the array I am iterating would still be 1,2,3,4,5.
Which I think it would be fine, because at the end I still get what I want, which removed the element and added the element I need. However modifying the list while iterating it is bad and you shouldn't do that, but for my case I think it does what I need. What could be the potential issue in my case that I can't see?
One thing you may want to think about doing is making all of the changes at the end of the iteration. Instead of making the changes one by one, record the changes you want to make while iterating, and then actually make those changes once your loop is finished.
For example, you could make an array of elements to remove, and an array of elements to add.
//Our array where we record what we want to add
var elementsToAdd = [Any]()
//Our array of what elements we want to remove. We record the index at
//which we want to remove the element from the array
var indexesToRemoveAt = [Int]()
//Getting all the children in array
var arr = parent.allchildren()
//Enumerating an array allows us to access the index at which that
//element occurs. For example, the first element's index would be 0,
//the second element's index would be 1, the third would be 2, and so
//on
for (index,ele) in arr.enumerated() {
if(ele == somethingHere) {
indexesToRemoveAt.append(index)
elementsToAdd.append(newEle)
}
}
//Now that we have recorded the changes we want to make, we could make
//all of the changes at once
arr.remove(at: indexesToRemoveAt)
arr.append(contentsOf: elementsToAdd)
Note that removing array elements at multiple indexes would require the following extension to Array. If you wanted to avoid creating this extension, you could always just loop through the array of indexes and tell the array to remove at each individual index. All this extension function is really doing is looping through the indexes, and removing the array element at said index.
Array extension to remove elements at multiple indexes:
extension Array {
//Allows us to remove at multiple indexes instead of just one
mutating func remove(at indexes: [Int]) {
for index in indexes.sorted(by: >) {
if index <= count-1 {
remove(at: index)
}
}
}
}
I just tested in a playground with the following code:
var arr = ["hi", "bye", "guy", "fry", "sky"]
for a in arr {
if arr.count >= 3 {
arr.remove(at: 2)
}
print(a)
}
print(arr)
This prints:
hi
bye
guy
fry
sky
["hi", "bye"]
So it looks like when you use a for-in loop in Swift, the array is copied and changes you make to it will not affect the array you are iterating over. To answer your question, as long as you understand that this is the behavior, there's nothing wrong with doing this.

Recursive function not breaking

I want to iterate over a 2D array and make subarrays whenever I find a different value in a specific column. Example:
TEST <----- This value should be ignored. Start counting at index 1.
A
A
A
-------- split here --------
B
B
B
-------- split here --------
C
-------- split here --------
This results in 3 arrays.
array1: [A,A,A]
array2: [B,B,B]
array3: [C]
My solution to this problem was a recursive method which takes the 2D array:
static func splitArray(fromArray array: [[String]], startIndex: Int = 1) {
for x in startIndex..<array.count {
if array.indices.contains(x+1) {
if (array[x][7]) != array[x+1][7] {
splitArray(fromArray: array, startIndex: x+1)
}
} else {
break
}
}
}
In this method I do the following:
Go through the array starting at index 1.
Compare the current index with the next index. If the next index has a different value split the array if not resume iterating.
To prevent array out of bounds I check if there's a next index - if there is no next index break the method (which should be called once the whole array has been iterated over)
Extra info:
The magic number 7 is the column in my 2D array I want to iterate over.
The method does reach the break command .. but somehow it jumps back in the method although it doesn't get called by the recursive splitArray call.
This method doesn't create the subarrays yet since the logic at this point is broken.
Why doesn't my function break? It does do its work - it splits correctly but then it starts over when it shouldn't.
P.S: If there's any coding advice I'd highly appreciate it, I feel this code in general is bad.
Solved it:
static func split(_ array: [[String]], startIndex: Int = 1) {
for x in startIndex..<array.count {
if array.indices.contains(x+1) {
if (array[x][7]) != array[x+1][7] {
split(array, startIndex: x+1)
break
}
}
}
}
The "fix" was to include the break after calling the recursive function. I guess the for loop resumed after calling split.

Why does this simple array access not work in Swift?

var word = "morning"
var arr = Array(word)
for s in 0...word.count {
print(arr[s])
}
This will not print. Of course, if I substitute a number for s, the code works fine.
Why will it not accept a variable in the array access braces? Is this peculiar to Swift?
I've spent a long time trying to figure this out, and it's nothing to do with s being optional.
Anyone understand this?
you are using inclusive range ... instead of ..<, so s goes from 0 to 7, not 0 to 6.
However, in arr the index goes from 0 to 6 because there are 7 characters.
Thus, when the program tries to access arr[7], it throws an index out of range error.
If you were coding on Xcode, the debugger would have told you that there is no arr[7].
As for the code, here is a better way to print every item in arr than using an index counter:
var word = "morning"
var arr = Array(word)
for s in arr {
print(s)
}
This is called a "foreach loop", for each item in arr, it assigns it to s, performs the code in the loop, and moves on to the next item, assigns it to s, and so on.
When you have to access every element in an array or a collection, foreach loop is generally considered to be a more elegant way to do so, unless you need to store the index of a certain item during the loop, in which case the only option is the range-based for loop (which you are using).
Happy coding!
When I run it, it prints the array then throws the error Fatal error: Index out of range. To fix this, change the for loop to:
for s in 0..<word.count {
print(arr[s])
}
try this
when you use a word to recognize
size of Array your Array index start as 0 so array last index must be equal with your (word.count - 1)
var word = "morning"
var arr = Array(word)
for s in 0...(word.count-1) {
print(arr[s])
}
Basically avoid index based for loops as much as possible.
To print each character of a string simply use
var word = "morning"
for s in word { // in Swift 3 word.characters
print(s)
}
To solve the index issue you have to use the half-open range operator ..< since indexes are zero-based.

Resources