I am looking for an elegant way to iterate through an array and assign each of its values to one or more of five UILabels
This code illustrates what I am trying to do (although it is very long and repetitive)
if touches.count >= 1 {
positionTouch1LBL.text = String(describing: touches[0].location(in: view))
} else {
positionTouch1LBL.text = "0.0 / 0.0"
}
if touches.count >= 2 {
positionTouch2LBL.text = String(describing: touches[1].location(in: view))
} else {
positionTouch2LBL.text = "0.0 / 0.0"
}
if touches.count >= 3 {
positionTouch3LBL.text = String(describing: touches[2].location(in: view))
} else {
positionTouch3LBL.text = "0.0 / 0.0"
}
if touches.count >= 4 {
positionTouch4LBL.text = String(describing: touches[3].location(in: view))
} else {
positionTouch4LBL.text = "0.0 / 0.0"
}
if touches.count >= 5 {
positionTouch5LBL.text = String(describing: touches[4].location(in: view))
} else {
positionTouch5LBL.text = "0.0 / 0.0"
}
You could put your labels inside another array and iterate through them:
let labelsArray = [positionTouch1LBL, positionTouch2LBL, positionTouch3LBL, positionTouch4BL, positionTouch5LBL]
for i in 0..<labelsArray.count {
// Get i-th UILabel
let label = labelsArray[i]
if touches.count >= (i+1) {
label.text = String(describing: touches[i].location(in: view))
}else{
label.text = "0.0 / 0.0"
}
}
This way you are able to group redundant code
You could do that by putting your labels in an array and iterate through them in the following way:
let labelsArray = [UILabel(), UILabel(), ... ] // An array containing your labels
for (index, element) in labelsArray.enumerated() {
if index < touches.count {
element.text = String(describing: touches[index].location(in: view))
} else {
element.text = "0.0 / 0.0"
}
}
Good luck!
Related
I have an issue where I am calling a function, it's appending an array, and then I get a random element from it, the problem is that is keeps getting wiped right after the function is called before I can use it, therefore, the random element request is causing a fatal error.
Utilities.getKnockKnockJokes {
self.previousKnockKnockJoke = self.currentKnockKnockJoke
print("currentKnockKnockJoke = \(self.currentKnockKnockJoke)")
self.currentKnockKnockJoke = KnockKnockJokes.knockKnockJokes.randomElement()!
print("newCurrentKnockKnockJoke = \(self.currentKnockKnockJoke)")
self.singleServeText.text = self.currentKnockKnockJoke
}
The function called is below:
static func getKnockKnockJokes(completion: #escaping () -> Void) {
let db = Firestore.firestore()
let group = DispatchGroup()
group.enter()
DispatchQueue.global(qos: .background).async {
print("countKnockKnockJokes = \(self.countKnockKnockJokes)")
if self.countKnockKnockJokes == 0 {
while self.countKnockKnockJokes == 0 {
if self.countKnockKnockJokes == 0 {
self.countKnockKnockJokes = 1
group.leave()
}else {
print("leaving")
group.leave()
}
}
}else {
print("skipped")
group.leave()
}
}
group.notify(queue: .main) {
db.collection("jokes").document("Knock Knock Jokes").addSnapshotListener { document, error in
//check for error
if error == nil {
//check if document exists
if document != nil && document!.exists {
if let JokeNum = document!.get("JokeNum") as? Int {
self.countKnockKnockJokes = JokeNum
UserDefaults.standard.setValue(JokeNum, forKey: "countKnockKnockJokes")
print("KnockKnockJokeNum = \(self.countKnockKnockJokes)")
}
var count = 1
print("count = \(count)/\(self.countKnockKnockJokes)")
print("countKnockKnockJoke = \(self.countKnockKnockJokes)")
//Utilities.knockKnockJokes.removeAll()
KnockKnockJokes.knockKnockJokes.removeAll()
for _ in 0...self.countKnockKnockJokes {
print("count = \(count)/\(self.countKnockKnockJokes)")
if let Joke = document!.get("\(count)") as? String {
print("KnockKnockJokeNum = \(self.countKnockKnockJokes)")
if Utilities.jokes.contains("\(Joke) - From Knock Knock Jokes") {}else {
print("Joke = \(Joke)")
Utilities.jokes.append("\(Joke) - From Knock Knock Jokes")
KnockKnockJokes.knockKnockJokes.append(Joke)
print("KnockKnockJokes = \(KnockKnockJokes.knockKnockJokes)")
UserDefaults.standard.set(KnockKnockJokes.knockKnockJokes, forKey: defaults.knockKnockJokes.rawValue)
Utilities.updateJokesDefaults()
}
print("countKnockKnockFinal = \(count)/\(self.countKnockKnockJokes)")
if count == self.countKnockKnockJokes {
completion()
}
count = count + 1
}
}
}
}
}
}
}
try this:
if count == self.countKnockKnockJokes {
completion()
return // <--- here
}
I fixed it, my remove all was running after all the appends.
It is saying "error, index out of range"
I already tried making it a 0..< that still returns the error. Been looking over the code for 30 minutes can't figure out what I messed up
func kidsWithCandies(_ candies: [Int], _ extraCandies: Int) -> [Bool] {
var greatestCandyNum = 0
var arrayOfBools = Array<Bool>()
for kid in candies {
if candies[kid] > greatestCandyNum {
greatestCandyNum = candies[kid]
arrayOfBools.append(false)
}
}
for kid in candies {
if candies[kid] + extraCandies >= greatestCandyNum{
arrayOfBools[kid] = true
}
}
for kid in candies {
if candies[kid] == greatestCandyNum {
arrayOfBools[kid] = true
} else if candies[kid] > greatestCandyNum {
greatestCandyNum = candies[kid]
arrayOfBools[kid] = true
}
}
return arrayOfBools
}
So the main issue is that you cannot pass the value from the for loop into the index of the array. You can use the enumerate function to generate the index of where you are in the array position.
As seen with:
for (index, kid) in candies.enumerated()
I also fixed your initial for loop that would not generate a consistent Bool array if your candies array was not ascending. This was done with an else
Also please see that when iterating you can use the "kid" value rather than trying to find it again in the array.
Disclaimer: There are however much better ways of doing this.
func kidsWithCandies(_ candies: [Int], _ extraCandies: Int) -> [Bool] {
var greatestCandyNum = 0
var arrayOfBools = Array<Bool>()
for kid in candies {
if kid > greatestCandyNum {
greatestCandyNum = kid
arrayOfBools.append(false)
} else {
arrayOfBools.append(true)
}
}
for (index, kid) in candies.enumerated() {
if kid + extraCandies >= greatestCandyNum {
arrayOfBools[index] = true
}
}
for (index, kid) in candies.enumerated() {
if kid == greatestCandyNum {
arrayOfBools[index] = true
} else if kid > greatestCandyNum {
greatestCandyNum = kid
arrayOfBools[index] = true
}
}
return arrayOfBools
}
My ambition is to have a Dictionary that contains (among other things) an array and being able to get out the values of that array.
var total: Int = 0;
let dice:[NSTextField:NSArray] = [
d4Amount:[d4OE, 4],
d6Amount:[d6OE, 6],
];
for (die, dieArray) in dice
{
let button:NSButton = dieArray[0] as! NSButton;
let num:Int = dieArray[1] as! Int;
total += DoRoll(die, oe: button, max: num);
}
In the above the line "let button:NSButton = dieArray[0]..." get's the error Thread 1: signal SIGABRT and the program fails.
First I only had the line:
total += DoRoll(die, oe: dieArray[0] as! NS Button, max: dieArray[1] as! Int);
Which didn't either work (quite obviously), but however when I do this, it works...
total += DoRoll(d4Amount, oe: d4OE, max: 4);
It works perfectly.
Any ideas??
The function DoRoll looks like this (which should not be relevant):
private func DoRoll(amount: NSTextField, oe: NSButton, max: Int) -> Int
{
let nrRolls: Int! = Int(amount.stringValue);
var total: Int = 0;
if(nrRolls != nil && nrRolls != 0)
{
OutputText.string = OutputText.string! + "Now rolling d" + String(max) + ": ";
for(var i: Int = 0; i < nrRolls; i++)
{
var randomNr: Int, specialMax: Int;
var textStr: String = "";
specialMax = max;
if(max >= 100)
{
if(max > 100)
{
specialMax = 995;
}
else if(max > 99)
{
specialMax = 95;
}
else
{
specialMax = max - 1;
}
}
repeat
{
randomNr = Int(arc4random_uniform(UInt32(max))) + 1;
total += randomNr;
if(textStr != "") { textStr = textStr + "+"; }
textStr = textStr + String(randomNr);
} while(oe.state == NSOnState && randomNr >= specialMax)
OutputText.string = OutputText.string! + textStr + " ";
}
OutputText.string = OutputText.string! + "\n";
}
return total;
}
I now know what I did wrong.
This is not at all a case of error in the code above but in the naming of items in the project. I had several different D4Amount in the same project in the View and thus that was why it crashed.
Sorry to bother you.
I like to sort an array with objects that have multiple properties. My objects have a string called name and a boolean called mandatory.
First i want to sort on age, next on the name.
How do I do this?
Ordering by age is easy...:
this.model.mylist.sort((obj1: IObj, obj2: IObj => {
if (obj1.age < obj2.age) {
return -1;
}
if (obj1.age > obj2.age) {
return 1;
}
return 0;
});
Well, you only add comparation for case when the two age values are the same. So something like this should work:
this.model.mylist.sort((obj1: IObj, obj2: IObj) => {
if (obj1.age < obj2.age) {
return -1;
}
if (obj1.age > obj2.age) {
return 1;
}
return obj1.name.localeCompare(obj2.name);
});
Something like this should work. The method compares the current and next values and adds comparison to the case when the two age values are the same. Then assume the column name in order based on age.
private compareTo(val1, val2, typeField) {
let result = 0;
if (typeField == "ftDate") {
result = val1 - val2;
} else {
if (val1 < val2) {
result = - 1;
} else if (val1 > val2) {
result = 1;
} else {
result = 0;
}
}
return result;
}
-
this.model.mylist.sort((a, b) => {
let cols = ["age", "name"];
let i = 0, result = 0, resultordem = 0;
while (result === 0 && i < cols.length) {
let col = cols[i];
let valcol1 = a[col];
let valcol2 = b[col];
let typeField = "string";
if (col == "age") {
typeField = "number";
}
if (valcol1 != "null" && valcol1 != "null") {
resultordem = this.compareTo(valcol1, valcol2, typeField);
if (resultordem != 0) {
break;
}
}
i++;
}
return resultordem;
});
I have an array of objects. Each object has a color attribute which could be "red", "blue", "yellow", "green", "orange" or "purple". There are 20-30 objects in the array so colors repeat. My goal is to sort the array so that no colors are next to each other. Distribution of colors is not exactly even but close.
This is what I have so far. It checks the next and previous object for a color match and if it finds a match it moves it to the end of the array.
private function sortColors():void
{
var getNext:uint;
var getPrev:uint;
var maxCount:uint = colorArray.length;
for (var i:uint = 0; i < maxCount; i++) {
var cur:ValueObject = colorArray[i];
(i == maxCount-1) ? getNext = 0 : getNext = i+1;
(i == 0) ? getPrev = maxCount-1 : getPrev = i-1;
var next:ValueObject = colorArray[getNext];
var prev:ValueObject = colorArray[getPrev];
if (cur.color == next.color) {
var move:ValueObject = colorArray[getNext];
colorArray.splice(getNext, 1);
colorArray.push(move);
}
if (cur.color == prev.color) {
var move:ValueObject = colorArray[getPrev];
colorArray.splice(getPrev, 1);
colorArray.push(move);
}
}
}
This works OK but if there is more of a certain color they end up repeating at the end. I could add something to the end to throw those back into the mix but I feel like there must be a better way. Someone enlighten me.
Try:
var colorObjects:Array = [/* list of objects with colors - populated below*/];
var jumbled:Array = [];
var lastColor:String = "";
function getDifferentTile():void
{
if(lastColor.length == 0)
{
jumbled.push(colorObjects.pop());
lastColor = jumbled[0].mycolor;
}
else
{
var i:Object;
for each(i in colorObjects)
{
var repeat:uint = 0;
if(i.mycolor != lastColor)
{
jumbled.push(i);
lastColor = i.mycolor;
colorObjects.splice(colorObjects.indexOf(i), 1);
return;
} else {
repeat++;
}
if (repeat > 0 && repeat == colorObjects.length) {
jumbled.push(i);
colorObjects.splice(colorObjects.indexOf(i), 1);
return;
}
}
}
}
// list of random colors
var colors:Array = ["0x000000","0x444444","0xFFFFFF","0xFF00FF"];
// prepare random array for test
var i:uint = 0;
for(i; i<100; i++)
{
var obj:Object =
{
mycolor: colors[uint(Math.random()*colors.length)]
};
colorObjects.push(obj);
}
// fill the jumble array until the original listing is empty
while(colorObjects.length > 0)
{
getDifferentTile();
}
// output jumbled
var j:Object;
for each(j in jumbled)
{
trace(j.mycolor);
}