How to safely pass an array as parameter in swift - swift

Hi this is my first question posted here. I have a class which updates an array from a stream of audio samples which I periodically need to process within another class. This is the code that updates the array and removes the oldest element when it reaches a maximum size:
public func update(sample: Sample) {
lastPeak = abs(sample.val) > abs(lastPeak) ? sample.val : lastPeak
if let last = lastSample {
if last.val * sample.val < 0 && abs(lastPeak) > minPeakSize { // this is a zero crossing
let offset = Double(sample.index) + Double(round((sample.val/(last.val - sample.val)) * 100) / 100)
let crossing = ZeroCrossing(
index: sample.index,
previousPeak: lastPeak,
indexWithOffset: offset
)
self.crossings.array.append(crossing) \\ <-- ARRAY UPDATE
lastPeak = 0
while crossings.array.count > crossingsMaxSize {
crossings.array.remove(at: 0) \\ <--ARRAY RESIZE
}
}
}
lastSample = sample
I then pass the array to a method within a separate class and occasionally get an index out of range error.
mutating func run(crossings: Crossings, octave: Int = 2) -> CorrelationResult? {
var result: CorrelationResult? = nil
if crossings.array.count > 4 {
var lastIndex: UInt = 0
if let lastCrossing = crossings.array.last {
lastIndex = lastCrossing.index
}
var startPoint = 0
var completeSet = false
for (i, crossing) in crossings.array.reversed().enumerated() { \\ <-- INDEX OUT OF RANGE
if lastIndex > crossing.index {
if lastIndex - crossing.index > windowSizeForOctave[octave] && crossing.previousPeak < 0 {
startPoint = crossings.array.count - i
completeSet = true
break
}
}
}
The array is wrapped within a struct
struct Crossings {
var locked = false
var array = [ZeroCrossing]()
}
struct ZeroCrossing {
var index: UInt
let previousPeak: Float
let indexWithOffset: Double
}
When the error occurs the array contains 500 elements and i = 0. Is there a safe way to pass arrays between classes (and I assume threads) without blocking updates to the original array?

Related

How can I change my recursive code to connect all tiles without crossing a tile more than once?

Here's a picture of what I am trying to make my Swift code do:
I have marked the tiles with numbers. Tile 3 and 8 is disabled. 6 is the starting point and 0 is the goal.
NOTE: The start point is specified but the end point is not. End point can be any where as long as the path goes through all the tiles. In my example, I just specified 0 to make it easy but it's not actually going to be specified.
I am only allowed to go horizontal or vertical. There's more than one way to get to the goal but I need to find the path which goes through all numbers once. I have marked this path in the image (6,7,4,5,2,1,0).
Right now I have the following code which first gets all the direct connections of each tile then uses recursion to find the path. Currently my code gives me the path 6,7,4,1,0 which doesn't go through 5 & 2 and hence isn't what I want.
I am not sure how to change my code to get the path which goes through all tiles.
let size = (rows: 3, columns: 3)
let off = [3,8]
let start : Int = 6
let finish : Int = 0
var connections = [Int:[Int]]()
var path = [Int]()
var visited = [Int]()
func backtrackingStuff() {
for index in 0..<size.rows * size.columns {
if !off.contains(index) {
let rowStart : Int = index - index%size.columns
let rowEnd : Int = rowStart + size.columns - 1
var temp = [Int]()
let possibleUpperConnection : Int = index - size.columns
if possibleUpperConnection >= 0 && !off.contains(possibleUpperConnection) {
temp.append(possibleUpperConnection)
}
let possibleBottomConnection : Int = index + size.columns
if possibleBottomConnection <= (size.rows * size.columns - 1) && !off.contains(possibleBottomConnection) {
temp.append(possibleBottomConnection)
}
let possibleLeftConnection : Int = index - 1
if possibleLeftConnection >= rowStart && !off.contains(possibleLeftConnection) {
temp.append(possibleLeftConnection)
}
let possibleRightConnection : Int = index + 1
if possibleRightConnection <= rowEnd && !off.contains(possibleRightConnection) {
temp.append(possibleRightConnection)
}
connections[index] = temp
}
}
print("V: \(NSSet(array: Array(connections.keys)))")
getPaths(currentPosition: start)
print("Path: \(path)")
}
func getPaths (currentPosition : Int) -> Bool {
//if NSSet(array: possiblePath).isEqual(to: NSSet(array: Array(connections.keys)) as! Set<AnyHashable>) { {
if currentPosition == finish {
path.insert(currentPosition, at: 0)
return true
}
visited.append(currentPosition)
if let connectionsForThisIndex = connections[currentPosition] {
for newIndex in connectionsForThisIndex {
if !visited.contains(newIndex) {
if getPaths(currentPosition: newIndex) {
path.insert(currentPosition, at: 0)
return true
}
}
}
}
return false
}

cannot assign through subscript in swift

I am trying to implement common alghorithm in Swift.
Even though I did not define numbers as a let variable, but I am getting following error:
cannot assign through subscript: 'numbers' is a 'let' constant
numbers[i] = maxNumber
My Implementation is as follows:
func InsertionSort (numbers : [Int]) -> [Int]
{
var maxNumber = 0
var j = 0
var size = numbers.count-1
for (i,number) in numbers.enumerated()
{
j = i + 1
for index in j...size
{
if numbers[index] > number
{
maxNumber = numbers[index]
numbers[index] = numbers[i]
// error is thrown in the following line
numbers[i] = maxNumber
}
}
}
return numbers
}
Parameters are immutable by default. To make a parameter mutable, you need to add an inout modifier.
However, seeing that your method returns an array, you probably don't want the parameter to be modified as well. You should instead make a copy of the parameter, modify that, and return the copy:
func InsertionSort (numbers : [Int]) -> [Int]
{
var maxNumber = 0
var j = 0
let size = numbers.count-1
var numbersCopy = numbers // <------ note this line
for (i,number) in numbers.enumerated()
{
j = i + 1
for index in j...size
{
if numbers[index] > number
{
maxNumber = numbers[index]
// note how I modified the copy here
numbersCopy[index] = numbers[i]
numbersCopy[i] = maxNumber
}
}
}
return numbersCopy
}

rawValue ++max is deprecated swift 3

I have this problem I can not solve. paste my code
static let count: Int = {
var max: Int = 0
while let _ = PDFList(rawValue: ++max) {}
return max
}()
}
I tried to write this but it does not work
rawValue: (max += 1)) {}
if you help me please. Thank you
+= is not an expression like ++, it's a statement. That is, it doesn't evaluate to a value that can be used in assignment, as a parameter, etc.
You have to split it apart, then use max directly:
static let count: Int = {
var max = 0
while let _ = PDFList(rawValue: max) { max += 1 }
return max
}()
This is more clear, IMO:
static let count: Int = {
var max = 0
while PDFList(rawValue: max) != nil { max += 1 }
return max
}()
The functional way to do this is:
static let count: Int = {
let max = (1 ... Int.max)
.first { PDFList(rawValue: $0) == nil }
return max!
}()
The original code never checks 0 and I am not sure whether that's correct. If it's not correct, change the lower bound of the range to 0.

EXC_I386_GPFLT in Swift code using Xcode Playground

I ran the same code in Xcode 7beta/rc Playground project and got an error:
Execution was interrupted, reason: EXC_BAD_ACCESS(code=EXC_I386_GPFLT)
in
let n: Int = Int(Process.arguments[1])!
How do I solve in Playground project since other solutions don't seem to be related?
Binary tree: http://benchmarksgame.alioth.debian.org/u64q/program.php?test=binarytrees&lang=swift&id=1
class TreeNode {
var left, right : TreeNode?
var item : Int
init(_ left: TreeNode?, _ right: TreeNode?, _ item: Int) {
self.left = left
self.right = right
self.item = item
}
func check() -> Int {
guard let left = left, let right = right else {
return item
}
return item + left.check() - right.check()
}
}
func bottomUpTree(item: Int, _ depth: Int) -> TreeNode {
if depth > 0 {
return
TreeNode(
bottomUpTree(2*item-1, depth-1),
bottomUpTree(2*item, depth-1),
item
)
}
else {
return
TreeNode(nil,nil,item)
}
}
let n: Int = Int(Process.arguments[1])!
let minDepth = 4
let maxDepth = n
let stretchDepth = n + 1
let check = bottomUpTree(0,stretchDepth).check()
print("stretch tree of depth \(stretchDepth)\t check: \(check)")
let longLivedTree = bottomUpTree(0,maxDepth)
var depth = minDepth
while depth <= maxDepth {
let iterations = 1 << (maxDepth - depth + minDepth)
var check = 0
for i in 0..<iterations {
check += bottomUpTree(i,depth).check()
check += bottomUpTree(-i,depth).check()
}
print("\(iterations*2)\t trees of depth \(depth)\t check: \(check)")
depth += 2
}
print("long lived tree of depth \(maxDepth)\t check: \(longLivedTree.check())")
Process.arguments holds the value that is passed as arguments for a command-line application.
But you're using it in a Playground: there's no access to command line input from a Playground (they are Sandboxed), so Process.arguments is nil and your app crashes when you're doing Process.arguments[1].
The solution is to use this in an actual application, not in a Playground.
You can use a custom "readLine()" function and a global input variable, each element in the input array is presenting a line:
import Foundation
var currentLine = 0
let input = ["5", "5 6 3"]
func readLine() -> String? {
if currentLine < input.endIndex {
let line = input[currentLine]
currentLine += 1
return line
} else {
return nil
}
}
let firstLine = readLine() // 5
let secondLine = readLine() // 5 6 3
let thirdLine = readLine() // nil

swift string advancedBy is slow?

So I am writing in swift to practice some online judge.
Here's the issue: Longest Palindromic Substring
Given a string S, find the longest palindromic substring in S. You may assume that the maximum length of S is 1000, and there exists one unique longest palindromic substring.
So I am using dp to solve it in swift:
class Solution {
func longestPalindrome(s: String) -> String {
var hash = Array(count: s.characters.count, repeatedValue: Array(count: s.characters.count, repeatedValue: false))
for i in 0 ..< s.characters.count {
hash[i][i] = true
}
var maxStart = 0
var maxEnd = 0
var maxCount = 1
for i in 1.stride(through: s.characters.count - 1, by: 1) {
for j in 0 ..< s.characters.count - 1 {
if j + i < s.characters.count {
if isValidPalindrome(j, j + i, s, hash) {
hash[j][j + i] = true
if maxCount < i + 1 {
maxCount = i
maxStart = j
maxEnd = j + i
}
}
}
else {
break
}
}
}
// construct max palindrome string, swift string is so dummy
var str = ""
for i in maxStart...maxEnd {
let index = s.characters.startIndex.advancedBy(i)
str += String(s.characters[index])
}
return str
}
func isValidPalindrome(start: Int, _ end: Int, _ s: String, _ hash: [[Bool]]) -> Bool {
// end <= s's length - 1
let startIndex = s.startIndex.advancedBy(start)
let endIdnex = s.startIndex.advancedBy(end)
if end - start == 1 {
return s[startIndex] == s[endIdnex]
}
else {
let left = start + 1
let right = end - 1
return s[startIndex] == s[endIdnex] && hash[left][right]
}
}
}
I am thinking it's a correct one, but when I submit, always time exceeded for long strings like:
"kyyrjtdplseovzwjkykrjwhxquwxsfsorjiumvxjhjmgeueafubtonhlerrgsgohfosqssmizcuqryqomsipovhhodpfyudtusjhonlqabhxfahfcjqxyckycstcqwxvicwkjeuboerkmjshfgiglceycmycadpnvoeaurqatesivajoqdilynbcihnidbizwkuaoegmytopzdmvvoewvhebqzskseeubnretjgnmyjwwgcooytfojeuzcuyhsznbcaiqpwcyusyyywqmmvqzvvceylnuwcbxybhqpvjumzomnabrjgcfaabqmiotlfojnyuolostmtacbwmwlqdfkbfikusuqtupdwdrjwqmuudbcvtpieiwteqbeyfyqejglmxofdjksqmzeugwvuniaxdrunyunnqpbnfbgqemvamaxuhjbyzqmhalrprhnindrkbopwbwsjeqrmyqipnqvjqzpjalqyfvaavyhytetllzupxjwozdfpmjhjlrnitnjgapzrakcqahaqetwllaaiadalmxgvpawqpgecojxfvcgxsbrldktufdrogkogbltcezflyctklpqrjymqzyzmtlssnavzcquytcskcnjzzrytsvawkavzboncxlhqfiofuohehaygxidxsofhmhzygklliovnwqbwwiiyarxtoihvjkdrzqsnmhdtdlpckuayhtfyirnhkrhbrwkdymjrjklonyggqnxhfvtkqxoicakzsxmgczpwhpkzcntkcwhkdkxvfnjbvjjoumczjyvdgkfukfuldolqnauvoyhoheoqvpwoisniv"
I can get the correct result qahaq after some time, and I am wondering why it's so slow. If I write it in other language, not so bad.
I suspect the API s.startIndex.advancedBy(start) is causing it, but I checked the doc, no time complexity and no other ways to turn an int to the startIndex type?
Any ideas to replace advancedBy? Thank in advance.
For those having the same issue: I turned swift String into Array, and it gets much faster.
I also looked into Swift source code about the advancedBy implementation, it's a O(n) opreation, that's why it's slow.
For whom is interested in the implementation, take a look at https://github.com/apple/swift/blob/8e12008d2b34a605f8766310f53d5668f3d50955/stdlib/public/core/Index.swift
You will see advancedBy is merely multiple successor():
#warn_unused_result
public func advanced(by n: Distance) -> Self {
return self._advanceForward(n)
}
/// Do not use this method directly; call advanced(by: n) instead.
#_transparent
#warn_unused_result
internal func _advanceForward(_ n: Distance) -> Self {
_precondition(n >= 0,
"Only BidirectionalIndex can be advanced by a negative amount")
var p = self
var i : Distance = 0
while i != n {
p._successorInPlace()
i += 1
}
return p
}
This should do the trick. Before implementing it, I recommend checking out some explanations such as this guy's. https://www.youtube.com/watch?v=obBdxeCx_Qs. I'm not affiliated with him, though I do believe his video is somewhat useful.
func longestPalindrome(_ s: String) -> String {
var charArray = [Character("$"), Character("#")]
for i in s.characters {
charArray += [i, Character("#")]
}
charArray += [Character("#")]
var mir = 0, c = 0, r = 0, longestPalindromeIndex = 0, longestPalindromeLength = 0, ss = "", returnString = ""
var p = [Int]()
//MARK: For loop
for i in 0...(charArray.count - 1) {
p += [0, 0]
mir = 2 * c - i
if i < r {
p[i] = min(r - i, p[mir])
}
if i - (1 + p[i]) >= 0 && i + (1 + p[i]) < charArray.count - 1 {
while charArray[i + (1 + p[i])] == charArray[i - (1 + p[i])] {
p[i] += 1
}
}
if p[i] > longestPalindromeLength {
longestPalindromeIndex = i
longestPalindromeLength = p[i]
}
if i + p[i] > r {
c = i
r = i + p[i]
}
}//for loop
for i in Array(charArray[(longestPalindromeIndex - longestPalindromeLength)...(longestPalindromeIndex + longestPalindromeLength)]) {
ss = String(i)
if ss != "#" && ss != "$" && ss != "#" {
returnString += ss
}
}
return returnString
}//func