Index out of Range - Swift - arrays

var truthArray = [Bool]()
func isStrictlyIncreasing(sameSequence: [Int]) {
var truthArray = [Bool]()
for i in 0 ... sameSequence.count-1{
if sameSequence[i]<sameSequence[i+1] {
truthArray.append(true)
}
else {
truthArray.append(false)
}
}
}
func almostIncreasingSequence(sequence: [Int]) -> Bool {
for i in 0 ... sequence.count-1 {
var sameSequence = sequence
let number = sequence[i]
sameSequence.remove(at: i)
isStrictlyIncreasing(sameSequence: sameSequence)
sameSequence.insert(number, at: i)
}
if truthArray.contains(true) {
return true
}
else {
return false
}
}
In this certain code challenge on CodeFights, you are asked to determine if removing one of the numbers in an array can be removed to leave a strictly increasing sequence.
The things I have tried to clear this error are switching the index beginning at 1 and readjusting the code that way, reducing and increasing the index bounds by 1, and this is probably my third time rewriting this code. But since my knowledge is strictly limited, I can't get very creative with my solution.
The problem I have right now is an index out of range. I know exactly what this means, except I don't know which line of code is causing the problem and why. I would very much appreciate hints more than a direct solution, as I am a beginner and this is a good learning experience.
Any and all help is appreciated! If I can add to this question with more details don't hesitate to tell me! :)

in if sameSequence[i]<sameSequence[i+1] you will get out of range always
If sameSequence size is 10, the for will be invoked from i=0 to i=9 (10 times). The last iteration will try to access sameSequence[10] and you will have an out of bounds exception.
You can fix it by changing the loop to for i in 0..<sameSequence.count-1 { } but consider that this could have an impact on your algorithm and your problem solution

Related

SwiftUI Large Array (over 30K elements) taking forever to iterate over

I'm so confused as to what's going on but basically, this is my code. Maybe I just am stupid or do not enough above swift or something but I feel like this should take less than a second, but it takes a very long time to iterate through (i added the CFAbsoluteTimeGetCurrent) because I wanted to see how long each assignment took and they take around 0.0008949041366577148 seconds each, but over the span of 30K that adds up obviously. This is just test code but what I'm really trying to do is implement Agglomerative Clustering using a single linkage in Swift, at first I thought that my algorithm was written poorly but then I just tried to iterate over an array like this and it still took a long time. Does anyone know what's up?
I'm also aware that printing out statements in the console takes time but even after removing these statements the onAppear closure still took a while to finish.
Also sorry this is my first time ever posting on Stack Overflow so if please let me know if I should write my posts a certain way in the future.
#State private var mat: [Double?] = Array(repeating: nil, count: 30000)
var body: some View {
Text("HELLo")
.onAppear() {
for i in 0..<matrix.count {
let start = CFAbsoluteTimeGetCurrent()
mat[i] = 0
let diff = CFAbsoluteTimeGetCurrent() - start
print("HAC_SINGLELINK.init TIME: \(diff), ROW \(i) of \(matrix.count)")
}
}
}
I believe the time is caused by the number of modifications you do to your #State variable, which cause a lot of overhead.
With your initial code, on my machine, it took ~16 seconds. With my modified code, which does all of the modifications on a temporary non-state variable and then assigns to #State once, it takes 0.004 seconds:
.onAppear() {
let start = CFAbsoluteTimeGetCurrent()
var temp = matrix
for i in 0..<temp.count {
temp[i] = 0
}
let diff = CFAbsoluteTimeGetCurrent() - start
matrix = temp
print("HAC_SINGLELINK.init TIME: \(diff) \(matrix.count)")
}

Swift Array Get performance optimization

I have a following code. It contains getPointAndPos function that needs to be as fast as possible:
struct Point {
let x: Int
let y: Int
}
struct PointAndPosition {
let pnt: Point
let pos: Int
}
class Elements {
var points: [Point]
init(points: [Point]) {
self.points = points
}
func addPoint(x: Int, y: Int) {
points.append(Point(x: x, y: y))
}
func getPointAndPos(pos: Int) -> PointAndPosition? {
guard pos >= 0 && points.count > pos else {
return nil
}
return PointAndPosition(pnt: points[pos], pos: pos)
}
}
However, due to Swift memory management it is not fast at all. I used to use dictionary, but it was even worse. This function is heavily used in the application, so it is the main bottleneck now. Here are the profiling results for getPointAndPos function:
As you can see it takes ~4.5 seconds to get an item from array, which is crazy. I tried to follow all performance optimization techniques that I could find, namely:
Using Array instead of Dictionary
Using simple types as Array elements (struct in my case)
It helped, but it is not enough. Is there a way to optimize it even further considering that I do not change elements from array after they are added?
UPDATE #1:
As suggested I replaced [Point] array with [PointAndPosition] one and removed optionals, which made the code 6 times faster. Also, as requested providing the code which uses getPointAndPos function:
private func findPoint(el: Elements, point: PointAndPosition, curPos: Int, limit: Int, halfLevel: Int, incrementFunc: (Int) -> Int) -> PointAndPosition? {
guard curPos >= 0 && curPos < el.points.count else {
return nil
}
// get and check point here
var next = curPos
while true {
let pnt = el.getPointAndPos(pos: next)
if checkPoint(pp: point, pnt: pnt, halfLevel: halfLevel) {
return pnt
} else {
next = incrementFunc(next)
if (next != limit) {
continue //then findPoint next limit incrementFunc
}
break
}
}
return nil
}
Current implementation is much faster, but ideally I need to make it 30 times faster than it is now. Not sure if it is even possible. Here is the latest profiling result:
I suspect you're creating a PointAndPosition and then immediately throwing it away. That's the thing that's going to create a lot of memory churn. Or you're creating a lot of duplicate PointAndPosition values.
First make sure that this is being built in Release mode with optimizations. ARC can often remove a lot of unnecessary retains and releases when optimized.
If getPointAndPos has to be as fast as possible, then the data should be stored in the form it wants, which is an array of PointAndPosition:
class Elements {
var points: [PointAndPosition]
init(points: [Point]) {
self.points = points.enumerated().map { PointAndPosition(pnt: $0.element, pos: $0.offset) }
}
func addPoint(x: Int, y: Int) {
points.append(PointAndPosition(pnt: Point(x: x, y: y), pos: points.endIndex))
}
func getPointAndPos(pos: Int) -> PointAndPosition? {
guard pos >= 0 && points.count > pos else {
return nil
}
return points[pos]
}
}
I'd take this a step further and reduce getPointAndPos to this:
func getPointAndPos(pos: Int) -> PointAndPosition {
points[pos]
}
If this is performance critical, then bounds checks should already have been done, and you shouldn't need an Optional here.
I'd also be very interested in the code that calls this. That may be more the issue than this code. It's possible you're calling getPointAndPos more often than you need to. (Though getting rid of the struct creation will make that less important.)

In Swift, how does one assign Data to array of UInt32?

I have Swift code which reads a binary file representing a sequence of UInt32 values like this:
let fileData = binaryFile.readData(ofLength: 44)
guard fileData.count > 0 else { break }
let headerData = fileData.withUnsafeBytes {
Array(UnsafeBufferPointer<UInt32>(start: $0, count: 11))
}
let polyCount = headerData[1].bigEndian
let polyFlags = headerData[2].bigEndian
I'd not used the program containing this code for a while, but when returning to it recently, it still works as expected, but now gives a deprecation warning:
"withUnsafeBytes is deprecated: use withUnsafeBytes<R>(_: (UnsafeRawBufferPointer) throws -> R) rethrows -> R instead"
I've searched for quite a long time for an un-deprecated way to do this without success. There are many examples across the web (including in stackoverflow) but almost all of them written before this deprecation into effect. Frankly, I've fried my brain hunting and trying suggestions! I am prepared to accept that I'm missing something totally obvious ("If it's getting complicated, you're doing it wrong."), but I work in an environment where I have no colleagues to ask .. except here.
Any guidance would be much appreciated.
RamsayCons's own solution is nice, but what about the performance? I think, it could be better if we reduce all unnecessary operation.
extension Data {
func toArray<T>(type: T.Type) -> [T] where T: ExpressibleByIntegerLiteral {
Array(unsafeUninitializedCapacity: self.count/MemoryLayout<T>.stride) { (buffer, i) in
i = copyBytes(to: buffer) / MemoryLayout<T>.stride
}
}
}
measured performance gain depends, but number of execution per second is at least doubled. Bigger the data, bigger advantage!
self.dataArray = data.withUnsafeBytes{ Array($0.bindMemory(to: UInt32.self))}
Well, letting some time pass restored brain function! I found an answer (in stackoverflow, of course):
round trip Swift number types to/from Data
some way into that question/answer is:
extension Data {
func toArray<T>(type: T.Type) -> [T] where T: ExpressibleByIntegerLiteral {
var array = Array<T>(repeating: 0, count: self.count/MemoryLayout<T>.stride)
_ = array.withUnsafeMutableBytes { copyBytes(to: $0) }
return array
}
}
The trick is that Arrays are not necessarily stored in contiguous memory so simply copying enough bytes in order to the destination doesn't do it. I hope this helps the next person hunting with a fried brain!!

Looping through an array to get index of item - swift

I am trying to loop through an array of names to get the index of a certain string. I then want to set the index of my UIPicker to the said string.
I have the following code however this causes the app to crash due:
let index = self.nameArray.index(where: {$0 == assetArray[0].Owner })
scroll_owners.selectRow(index ?? 0, inComponent: 0, animated: true)
When debugging the index is getting a value of index 6176573120 which of course isn't in the range of my UIPicker so causes the crash.
Any ideas on why this may be happening?
Using the suggested answer throws the following error:
unrecognized selector sent to instance 0x101134af0'
There is definitely a match in assetArray[0] with the name that is being passed through.
Doing a bit more investigation trying to run the following line of code alone gives the same error:
scroll_owners.selectRow(0, inComponent: 0, animated: true)
Does this mean I'm missing a delegate method?
Asset Array and Name Array:
var assetArray : [Asset] = []
var nameArray = [String]()
EDIT:
func numberOfComponents(in pickerView: UIPickerView) -> Int {
return 1
}
self.scroll_owners.delegate = self
self.scroll_owners.dataSource = self
I've tried to get this working another way - I know this is an ugly way of doing it I'm just trying to see why the accepted swift way isn't working:
var i : Int = 0
while (nameArray[i] != name)
{
print(nameArray[i])
i=i+1
}
scroll_owners.selectRow(i, inComponent: 0, animated: true)
This section of code crashes and the while loops is never entered due to the index being out of bounds - does this mean the issue could be with nameArray?
i think the problem is that .index doesn't return an IndexPath.
But selectRow needs an indexPath as parameter.
.index
.selectRow
I have managed to solve this error myself in a slightly different way.
In my function which populates the nameArray and the UIPicker I have placed the following code:
var i : Int = 0
while (self.nameArray[i] != name)
{
print(self.nameArray[i])
i=i+1
}
self.scroll_owners.selectRow(i, inComponent: 0, animated: true)
The reason the code was crashing was due to the fact that the nameArray was not finishing being populated before I was trying to do the comparisons. I know this may not be the accepted swift way of doing this but it works.
The issues were caused due to the function being run on a seperate thread I believe.

Checking arrays in AS3

I'm collecting rows of answers from a database which are made in to arrays. Something like:
for (var i:int = 0; i < event.result.length; i++) {
var data = event.result[i];
var answer:Array = new Array(data["question_id"], data["focus_id"], data["attempts"], data["category"], data["answer"], data["correct"], data["score"]);
trace("answer: " + answer);
restoreAnswer(answer, i);
}
Now, if I trace answer, I typically get something like:
answer: 5,0,2,IK,1.a,3.1,0
answer: 5,0,1,IK,2.a,3.1,0
answer: 4,1,1,AK,3,3,2
From this we see that focus_id 0 (second array item) in question_id 5 (first array item) has been attempted twice (third array item), and I only want to use the last attempt in my restoreAnswer function.
My problem is that first attempt answers override the second attempts since the first are parsed last it seems. How do I go about only calling my restoreAnswer only when appropriate?
The options are:
1 attempts, correct score (2 points)
2 attempts, correct score (1 points)
1 attempt, wrong score (0 points)
2 attemps, wrong score (0 points)
There can be multiple focus_id in each question_id.
Thank you very much! :)
I would consider having the DB query return only the most recent attempt, or if that doesn't work efficiently, return the data in attempt order. You may score question 5 twice, but at least it'll score correctly on the last pass.
You can also filter or sort the data you get back from the server.
Michael Brewer-Davis suggested using the database query to resolve this; normally speaking, this would be the right solution.
If you wait until you get it back from the web method call or whatever in AS3, then consider creating an additional Vector variable:
var vAttempts:Vector.<Vector.<int>> = new Vector.<Vector.<int>>(this.m_iNumQuestions);
You mentioned that it seems that everything is sorted so that earlier attempts come last. First you want to make sure that's true. If so, then before you do any call to restoreAnswer(), you'll want to check vAttempts to make sure that you have not already called restoreAnswer() for that question_id and focus_id:
if (!vAttempts[data["question_id"]])
{
vAttempts[data["question_id"]] = new Vector.<int>(); // ensuring a second dimension
}
if (vAttempts[data["question_id"]].indexOf(data["focus_id"]) == -1)
{
restoreAnswer(answer, i);
vAttempts[data["question_id"]].push(data["focus_id"]);
}
So optimizing this just a little bit, what you'll have is as follows:
private final function resultHandler(event:ResultEvent):void {
var vAttempts:Vector.<Vector.<int>> = new Vector.<Vector.<int>>(this.m_iNumQuestions);
var result:Object = event.result;
var iLength:int = result.length;
for (var i:int = 0; i < iLength; i++) {
var data = result[i];
var iQuestionID:int = data["question_id"];
var iFocusID:int = data["focus_id"];
var answer:Array = [iQuestionID, iFocusID, data["attempts"],
data["category"], data["answer"], data["correct"], data["score"]];
trace("answer: " + answer);
var vFocusIDs:Vector.<int> = vAttempts[iQuestionID];
if (!vFocusIDs) {
vAttempts[iQuestionID] = new <int>[iFocusID];
restoreAnswer(answer, i);
} else if (vFocusIDs.indexOf(iFocusID) == -1) {
restoreAnswer(answer, i);
vFocusIDs.push(iFocusID);
}
}
}
Note: In AS3, Arrays can skip over certain indexes, but Vectors can't. So if your program doesn't already have some sort of foreknowledge as to the number of questions, you'll need to change vAttempts from a Vector to an Array. Also account for whether question IDs are 0-indexed (as this question assumes) or 1-indexed.

Resources