This question already has answers here:
Swift ternary operator compilation error
(2 answers)
Closed 6 years ago.
I want to rewrite the below code to use the conditional operator:
if indexPath.row == 0 {
cell.indentationLevel = kIndentFDA
} else {
cell.indentationLevel = kIndentCompleted
}
But when I write this:
indexPath.row == 0 ? cell.indentationLevel = kIndentFDA : cell.indentationLevel = kIndentCompleted
I get this compiler warning:
"Cannot assign to immutable expression of type 'Int'"
The problem is that you don't understand what the ternary operator is. It isn't for performing assignments within the branches; the branches are not executable statements. Rather, the branches are evaluated expressions; thus, you use the ternary operator in the rvalue of an assignment and the branch values themselves are what is assigned.
So, you are writing this (which is nonsense):
indexPath.row == 0 ? cell.indentationLevel = kIndentFDA : cell.indentationLevel = kIndentCompleted
What you mean is:
cell.indentationLevel = indexPath.row == 0 ? kIndentFDA : kIndentCompleted
I don't know what the warning it but it probably can't figure out the order to apply the operators. This should work.
cell.indentationLevel = indexPath.row == 0 ? kIndentFDA : kIndentCompleted
Related
Given a hashset h = [1,2,3,4,5] for example, the purpose is to count the number of unique element i such that h.contains(i+1).
I can write down swift code using reduce() as
h.reduce(0,{h.contains($1+1) ? $0 + 1 : $0})
But what if h is an array containing duplicates instead of a hashset? I first need to convert it into hashset and then using the above expression:
Set(h).reduce(0,{Set(h).contains($1+1) ? $0 + 1 : $0})
But in this way we calculated Set(h).count + 1 times of Set(h) as pointed out by #carpsen90, is there any way to write the code like
Set(h).reduce(0,{self.contains($1+1) ? $0 + 1 : $0})
without using a temporary variable to store Set(h)?
Every time you call Set(h) a new set is calculated, so in your example Set(h).reduce(0,{Set(h).contains($1+1) ? $0 + 1 : $0}) , Set(h) will be calculated h.count + 1 times. Having a variable let set = Set(h) is the way to go here :
let set = Set(h)
let result = set.reduce(0) {set.contains($1+1) ? $0 + 1 : $0}
He is an alternative way of getting the desired result :
Let's create a dictionary that indicates wether a number has appeared in h:
var dict = [Int: Bool].init(minimumCapacity: h.count)
for x in h {
if dict[x] == nil {
dict[x] = true
}
}
And then, for each h element, check that its successor appears in the dictionary :
var count = 0
for entry in dict {
if dict[entry.key + 1] == true {
count += 1
}
}
And you could check the result :
print(count) //4
The problem here is that your array might contain duplicates and to filter the duplicates the easiest way is to convert it into the Set. And the correct way to do that is to save the set in a new variable hence it is unavoidable.
Though you can still use the reduce method without converting your array into a set like this:
var tempH = [Int]()
let c = h.reduce(0) { (result, item) in
if (!tempH.contains(item)) {
tempH.append(item)
return h.contains(item+1) ? (result + 1) : result
}
else {return result}
}
But, as you can notice in above code, we have to use a temporary array to track our duplicates. Hence an extra variable seems unavoidable here. Though no Sets are being used in above code.
This question already has answers here:
Can I use the range operator with if statement in Swift?
(6 answers)
Closed 5 years ago.
if indexPath.row == 0 ... 11 {
}
That isn't working, it says Binary operator '==' cannot be applied to the operands of type 'Int' and 'CountableClosedRange.
(Purpose of this is to disable rows 0-12.)
What is the proper way to do this? Basic question but I don't know what to search Google for. Thanks in advance!
If I had to guess it would be:
for numero in 0 ... 11 {
if indexPath.row == numero {
}
}
For check between value
Use "~=" range operator.
And use as below
Ex.
if 0 ... 11 ~= indexPath.row {
print("IndexPath in between 0 to 11")
}
let indexPath = IndexPath(row: 4, section: 0)
if (0...10).contains(indexPath.row) {
print(indexPath.row) // 4
}
This checks whether the row of your indexPath is within the range of 0 - 10
You are comparing a range of integers against a single integer which does not work.
You need to check if the range contains the value
if (0...11).contains(indexPath.row) { ...
But in your case you can also simply check
if indexPath.row < 12
since the row will never be negative.
This question already has answers here:
How can I do a Swift for-in loop with a step?
(1 answer)
Express for loops in swift with dynamic range
(2 answers)
Closed 6 years ago.
for (var i = 1; i < 1024; i *= 2) {
print(i)
}
How can this be done with for in loop?
The given solution is for += operator not *= operator. Please provide a solution for *= thanks.
In Swift 3 you can do
for f in sequence(first: 1, next: { $0 < (1024 / 2) ? $0 * 2 : nil }) {
print(f)
}
The concept of the sequence function is described in the documentation.
Printing an infinite list is easy, the code would just be
for f in sequence(first: 1, next: {$0 * 2}) {
print(f)
}
Since we want the program to stop at some point, we us the ternary operator ? to terminate the list once we reach the maximum value.
Since the last value we want to print is 512, the last value we have to double is 256. For 512 which does not satisfy the condition < (1024 / 2) we have nil and thereby stop.
This question already has answers here:
Use logical operator as combine closure in reduce
(6 answers)
Closed 6 years ago.
If I wish to calculate if all Bools in the list are true with this snippet, why won't the types be correctly inferred?
let bools = [false, true, false, true]
let result = bools.reduce(true, combine: &&)
I encountered the same bug a while ago (but then with ||). If you want to use reduce for this, the easiest solution is to write
let result = bools.reduce(true, combine: { $0 && $1 })
or
let result = bools.reduce(true) { $0 && $1 }
instead. As pointed out in the comments, you can also use
let result = !bools.contains(false)
Not only is this more readable, but it's also more efficient because it will stop at the first encounter of false rather than iterating over the entire array (though the compiler might optimize this).
I am trying to set multiple integer tests for a single variable in the if statement. The logical operators won't work due to the fact that they must be boolean.
For example:
if self.nodeAtPoint(location) == self.fake {
groundspeed = 35.0
self.button1value++
if(button1value == 2) {
groundspeed = 5.0
}
if(button1value == 4){
groundspeed = 5.0
}
if(button1value == 6) {
groundspeed = 5.0
}
}
The goal is to be able to put all of the even numbers shown into just one if statement.
If we just want to check whether or not button1value is even, we can do that using the modulo (%) operator:
if button1value % 2 == 0 {
// button1value is even
groundspeed = 5.0
}
If we're checking for some other sort of set, we can use a switch statement:
switch button1value {
case 2,4,6:
// button1value is 2, 4, or 6
groundspeed = 5.0
default:
// button1value is something else
}
We can do other neat tricks with Swift's switch statement too, if we want:
switch (button1value % 2, button1value % 3) {
case (0,0):
// button1value is an even multiple of 3 (6,12,18...)
case (0,_):
// button1value is an even number not a multiple of three (2,4,8,10,14...)
case (_,0):
// button1value is an odd multiple of three (3,9,15,21...)
default:
// button1value is none of the above: (1,5,7,11...)
}
Check and accept nhgrif's answer for a better variant. But just for the sake of completeness if you want to keep your way, you can use the logical OR operator ||
if(button1value == 2 || button1value == 4 || button1value == 6) {
groundspeed = 5.0
}
That checks if any of the given boolean-values is true.
There is also a logical AND operator &&.
You can use contains to check for multiple values. Just pass an array containing the values you want to test and the variable as the second parameter:
if contains([2, 4, 6], button1value) {
groundspeed = 5.0
}