I'm trying to write a function that has arrayOne, arrayTwo, and arrayThree as inputs. If arrayTwo has any 0s as its last elements, the function is supposed to remove these elements from the array, as well as the same elements from arrayOne. When I run the code and try to test it, I get the error: "Terminated by signal 4".
What could the problem be?
var arrayOneNew = arrayOne
var arrayTwoNew = arrayTwo
var arrayThreeNew = arrayThree
var endElement = arrayTwoNew.last
if endElement == 0 {
var counter = arrayTwoNew.count
while arrayTwoNew[counter] == 0 {
var elementToBeRemoved = arrayTwoNew.remove(at: counter - 1)
var 2ndElementToBeRemoved = arrayOneNew.remove(at: counter - 1)
}
}
Your main problem is that you are setting counter to arrayTwoNew.count which is 1 bigger than the last valid index in arrayTwoNew, so while arrayTwoNew[counter] == 0 crashes with index out of range.
Also:
var elementToBeRemoved = arrayTwoNew.remove(at: counter - 1)
is probably meant to remove the last item from arrayTwoNew, but that is more easily accomplished with:
arrayTwoNew.removeLast()
especially since you're not using elementToBeRemoved.
I think you're trying to do this:
while arrayTwoNew.last == 0 {
arrayTwoNew.removeLast()
arrayOneNew.removeLast()
arrayThreeNew.removeLast()
}
You are creating a new array "arrayTwoNew" which is mixed up with the original one at
var arrayTwoNew = arrayTwoNew.remove(at: counter - 1)
Now I'm also struggling with your .remove - this returns an element so won't work. I'd usually use a filter here but I'm not sure what you are doing!
//code with remove taken out (replace with filter?) to get you started:
let arrayOne = [1,2,3]
let arrayTwo = [2,3,4]
let arrayThree = [5,6,7]
var arrayOneNew = arrayOne
var arrayTwoNew = arrayTwo
var arrayThreeNew = arrayThree
var endIndex = arrayTwoNew.last
if endIndex == 0 {
let counter = arrayTwoNew.count
// arrayTwoNew = arrayTwoNew.remove(at: counter - 1)
while arrayTwoNew[counter] == 0 {
// arrayOneNew = arrayOneNew.remove(at: counter - 1)
}
}
Dispatching the queue messes up the order in the array as noted below. I'm trying to rank the array and then be able to translate it. So far its not working:
let top5 = Array(labels.sorted{ $0.confidence > $1.confidence}.prefix(upTo:5))
for lulu in top5 {
let translator = ROGoogleTranslate()
var params = ROGoogleTranslateParams()
params.source = "en"
params.target = "es"
params.text = "\(String(describing: lulu.label))"
translator.translate(params: params, callback: { (result) in
DispatchQueue.main.async {
self.textUno.text = self.textUno.text! + "\(lulu.label)" + " \(lulu.confidence*100)\n"
self.textDos.text = self.textDos.text! + "\(result)\n"
self.view.addSubview(self.textUno)
self.view.addSubview(self.textDos)
}
})
}
If I try to put the sorting out of DispatchQueue.main.async then the translation won't be lined up with the right word.
How can I fix this so that the array is sorted and the translation matches up ?
Translate the array first before ranking them.
Make it simpler first and make sure it is working and then put all the parts together.
If you really want to do it this way you will need to put them into a temporary array after sorting them and then use that at the end.
This, as you said, will return a jumbled result.
The below example is pretty close, needs a bit of a polish but you should be able to do it from this.
let top5 = Array(labels.sorted{ $0.confidence > $1.confidence}.prefix(upTo:5))
var tmparr : []
var count: Int = 0
for lulu in top5 {
let translator = ROGoogleTranslate()
count = count + 1
var params = ROGoogleTranslateParams()
params.source = "en"
params.target = "es"
params.text = "\(String(describing: lulu.label))"
params.ordernumber = count
translator.translate(params: params, callback: { (result) in
tmparr.append[params]
})
}
DispatchQueue.main.async {
for lulunew in tmparr {
if (lulunew.ordernumber == correctindex){
self.textUno.text = self.textUno.text! + "\(lulu.label)" + " \(lulu.confidence*100)\n"
self.textDos.text = self.textDos.text! + "\(result)\n"
self.view.addSubview(self.textUno)
self.view.addSubview(self.textDos)
}
}
}
I need to save files in an alphabetical order.
Now my code is saving files in numeric order
1.png
2.png
3.png ...
The problem is when i read this files again I read this files as described here
So I was thinking of changing the code and to save the files not in a numeric order but in an alphabetical order as:
a.png b.png c.png ... z.png aa.png ab.png ...
But in Swift it's difficult to increment even Character type.
How can I start from:
var s: String = "a"
and increment s in that way?
You can keep it numeric, just use the right option when sorting:
let arr = ["1.png", "19.png", "2.png", "10.png"]
let result = arr.sort {
$0.compare($1, options: .NumericSearch) == .OrderedAscending
}
// result: ["1.png", "2.png", "10.png", "19.png"]
If you'd really like to make them alphabetical, try this code to increment the names:
/// Increments a single `UInt32` scalar value
func incrementScalarValue(_ scalarValue: UInt32) -> String {
return String(Character(UnicodeScalar(scalarValue + 1)))
}
/// Recursive function that increments a name
func incrementName(_ name: String) -> String {
var previousName = name
if let lastScalar = previousName.unicodeScalars.last {
let lastChar = previousName.remove(at: previousName.index(before: previousName.endIndex))
if lastChar == "z" {
let newName = incrementName(previousName) + "a"
return newName
} else {
let incrementedChar = incrementScalarValue(lastScalar.value)
return previousName + incrementedChar
}
} else {
return "a"
}
}
var fileNames = ["a.png"]
for _ in 1...77 {
// Strip off ".png" from the file name
let previousFileName = fileNames.last!.components(separatedBy: ".png")[0]
// Increment the name
let incremented = incrementName(previousFileName)
// Append it to the array with ".png" added again
fileNames.append(incremented + ".png")
}
print(fileNames)
// Prints `["a.png", "b.png", "c.png", "d.png", "e.png", "f.png", "g.png", "h.png", "i.png", "j.png", "k.png", "l.png", "m.png", "n.png", "o.png", "p.png", "q.png", "r.png", "s.png", "t.png", "u.png", "v.png", "w.png", "x.png", "y.png", "z.png", "aa.png", "ab.png", "ac.png", "ad.png", "ae.png", "af.png", "ag.png", "ah.png", "ai.png", "aj.png", "ak.png", "al.png", "am.png", "an.png", "ao.png", "ap.png", "aq.png", "ar.png", "as.png", "at.png", "au.png", "av.png", "aw.png", "ax.png", "ay.png", "az.png", "ba.png", "bb.png", "bc.png", "bd.png", "be.png", "bf.png", "bg.png", "bh.png", "bi.png", "bj.png", "bk.png", "bl.png", "bm.png", "bn.png", "bo.png", "bp.png", "bq.png", "br.png", "bs.png", "bt.png", "bu.png", "bv.png", "bw.png", "bx.png", "by.png", "bz.png"]`
You will eventually end up with
a.png
b.png
c.png
...
z.png
aa.png
ab.png
...
zz.png
aaa.png
aab.png
...
Paste this code in the playground and check result. n numbers supported means you can enter any high number such as 99999999999999 enjoy!
you can uncomment for loop code to check code is working fine or not
but don't forget to assign a lesser value to counter variable otherwise Xcode will freeze.
var fileName:String = ""
var counter = 0.0
var alphabets = ["a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z"]
let totalAlphaBets = Double(alphabets.count)
let numFiles = 9999
func getCharacter(counter c:Double) -> String {
var chars:String
var divisionResult = Int(c / totalAlphaBets)
let modResult = Int(c.truncatingRemainder(dividingBy: totalAlphaBets))
chars = getCharFromArr(index: modResult)
if(divisionResult != 0){
divisionResult -= 1
if(divisionResult > alphabets.count-1){
chars = getCharacter(counter: Double(divisionResult)) + chars
}else{
chars = getCharFromArr(index: divisionResult) + chars
}
}
return chars
}
func getCharFromArr(index i:Int) -> String {
if(i < alphabets.count){
return alphabets[i]
}else{
print("wrong index")
return ""
}
}
for _ in 0...numFiles {
fileName = getCharacter(counter: counter)+".png"
print(fileName)
counter += 1
}
fileName = getCharacter(counter: Double(numFiles))+".png"
print(fileName)
func updateTotalScore() -> Int {
var totalScoreDefault = NSUserDefaults.standardUserDefaults()
var highScoreAB1 = defaults.integerForKey("highScoreAB1")
var highScoreAB2 = defaults.integerForKey("highScoreAB2")
var highScoreAB3 = defaults.integerForKey("highScoreAB3")
var highScoreAB4 = defaults.integerForKey("highScoreAB4")
var highScoreAB5 = defaults.integerForKey("HighScoreAB5")
var highScoreAB6 = defaults.integerForKey("highScoreAB6")
var highScoreAB7 = defaults.integerForKey("highScoreAB7")
totalScoreDefault =
(defaults.integerForKey("highScoreAB1") + defaults.integerForKey("highScoreAB2")) + (defaults.integerForKey("highScoreAB3") + defaults.integerForKey("highScoreAB4")) + (defaults.integerForKey("highScoreAB5") + defaults.integerForKey("highScoreAB6")) + defaults.integerForKey("highScoreAB7") }
Adding multiple keys to get a total score default throws the following error. I tried grouping them together into pairs, and that did not work. Thank you in advance. This is a continuation from a post from yesterday.
Just as an addition to Logan's answer, because you are saying that you have problems with "complex expression" compiler error. This should compile:
func updateTotalScore() -> Int {
let defaults = NSUserDefaults.standardUserDefaults()
let totalScoretDefault =
defaults.integerForKey("highScoreAB1") +
defaults.integerForKey("highScoreAB2") +
defaults.integerForKey("highScoreAB3") +
defaults.integerForKey("highScoreAB4") +
defaults.integerForKey("highScoreAB5") +
defaults.integerForKey("highScoreAB6") +
defaults.integerForKey("highScoreAB7")
return totalScoretDefault
}
It looks like you are trying to add all of the highscores up into one UserDefault named totalScoreDefault. If so, you need to be setting the totalScoreDefault like so:
default.setInteger(highScoreAB1 + ... + highScoreAB7, forKey: "totalScoreDefault")
// You can also consider adding all highScores up before
// this to make the setInteger portion look cleaner.
var totalScore = 0
for var i = 1; i < 8; i++ {
totalScore += defaults.integerForKey("highScoreAB\(i)")
}
defaults.setInteger(totalScore, forKey: "totalScoreDefault")
I'm trying to convert a length of time in "Hours:Minutes" to "minutes". Time is given as a String, and I want to return a Double of minutes.
Currently I'm using the following function:
func convertMinHoursToDouble(length: String) -> Double {
var hours = 0.0
var minutes = 0.0
let lengthCleaned = length.stringByReplacingOccurrencesOfString(":", withString: "")
var count = 0
for char in lengthCleaned.characters {
if count == 0 {
hours = Double("\(char)")! * 60
} else if count == 1 {
minutes = Double("\(char)")! * 10
} else if count == 2 {
minutes = Double("\(char)")! + minutes
}
++count
}
return hours+minutes
}
let time = "2:16"
let convertedTime = convertMinHoursToDouble(time)
print(convertedTime) // prints 136.0
This works, however I'm trying to do this in a more functional / Swift way. How can it be done with the reduce function. This is the closest I can get to the solution.
let convertedTime = time.characters.reduce(0) { (dub, char) in dub + Double(String(char))! }
The pure Swift way would be :
let time = "02:16"
let converted = time.characters.split(":")
.flatMap { Int(String($0)) }
.reduce(0) { $0 * 60 + $1 }
print(converted) //"136\n"
Functional solution:
func convertMinHoursToDouble(time: String) -> Int {
let timeComps = (time as NSString).componentsSeparatedByString(":") as [NSString]
return timeComps.reduce(0) { acc, item in
acc * 60 + item.integerValue
}
}
let time = "02:15"
let convertedTime = convertMinHoursToDouble(time)
print(convertedTime)
You split the string into components, and reduce on that array. This works like a charm also for strings like "03:24:34" for which it computes the time in seconds.
You can add additional validation logic if you want to deal with malformed strings: no ":", more than one ":", invalid minutes value (e.g. 78), etc.