What's the difference between a comma separated conditional and one that uses a double ampersand [duplicate] - swift

This question already has answers here:
Separating multiple if conditions with commas in Swift
(6 answers)
Closed 5 years ago.
I've recently come across this type of scenario using if/let and understand what it does thanks to this post. To my understanding, both conditions need to be met before the proceeding block is executed. I now have come to a point where I've seen it in a regular conditional statement:
if existingTextHasDecimalSeparator != nil, replacementTextHasDecimalSeparator != nil {
return false
} else {
return true
}
What's the difference between doing the above and simply using && as seen below?:
if existingTextHasDecimalSeparator != nil && replacementTextHasDecimalSeparator != nil {
return false
} else {
return true
}

There does not appear to be a difference between using && for grouping conditionals and using commas. I too have so far only seen it used with optional binding, but apparently it also works for regular conditionals, as the following snippet works fine.
let bool1 = true;
let bool2 = true;
if bool1 , bool2 {
print("true");
} else {
print("false")
}

The comma is used when optional binding with boolean conditions, for example if let a = a, a.isValid() whereas && is a typical AND operator

Related

How do I print the boolean value?

Okay, so I'm currently trying to write the code for a very inaccurate stoplight--one that is only meant to help me understand what I've learned, but I can't seem to figure it out! In my code, at the very end, I say print("Green Light!") after setting up a few variables, but I would like to indicate what the computer should do instead of flat out saying "print this phrase," if that makes sense... not sure it does.
How would I write this if I wanted to simply print the Boolean value of greenLight without saying print("Green Light!")?
I'm very much a beginner and I might be asking the wrong question--I know that, but I'm hoping someone can help!
Something tells me I haven't learned enough to do this, yet, but I really wanna know how this works.
This is what I've written so far. It runs, but I would like to change it so all I have to say is print(greenLight) or print(Bool).
When I try putting in print(greenLight), it returns an error:
Output:
Review.swift:14:7: error: variable 'greenLight' used before being initialized
print(greenLight)
^
Review.swift:4:5: note: variable defined here
var greenLight: Bool
^
var carAtRightIntersection = false
var carAtLeftIntersection = false
var carStraightAhead = true
var greenLight: Bool
if !(carAtRightIntersection && carAtLeftIntersection) && carStraightAhead {
greenLight = true
}
if carAtRightIntersection && carAtLeftIntersection && !(carStraightAhead) {
greenLight = false
}
print("Green light!")
Edit: I consulted a few coding friends, and they provided a very good solution! Provided here:
var carAtRightIntersection = false
var carAtLeftIntersection = false
var carStraightAhead = true
var colorOfLight: String = "Red"
if !(carAtRightIntersection && carAtLeftIntersection) && carStraightAhead {
colorOfLight = "Green"
}
/*
if carAtRightIntersection && carAtLeftIntersection && !(carStraightAhead) {
greenLight = false
}
*/
print(colorOfLight + " light :)")
If you don't want to print the actual phrases, You could use a switch case statement
switch greenLight{
case true:
print("Green Light!")
case false:
print("Red Light!")
default:
print("Yellow Light!")
}
After the first block executes

How can I write down a shortened if condition? [duplicate]

This question already has answers here:
How to check if an element is in an array
(18 answers)
How to compare one value against multiple values - Swift
(8 answers)
How to find index of list item in Swift?
(23 answers)
Closed 4 years ago.
Does anyone have an idea how to write the following code in a shortened form?
if self.atPoint(locationUser) == blueMarkArray[0] || self.atPoint(locationUser) == blueMarkArray[1] || self.atPoint(locationUser) == blueMarkArray[2] || self.atPoint(locationUser) == blueMarkArray[3] || self.atPoint(locationUser) == blueMarkArray[4] || self.atPoint(locationUser) == blueMarkArray[5] || self.atPoint(locationUser) == blueMarkArray[6]{
print("its here")
}
Furthermore, I don't want to commit myself to a fixed number of elements in the blueMarkArray array. It should be as variable as possible, because for example it can contain 4 elements, but also 12 elements.
For each answer I am very grateful.
EDIT:
How can you access the found element if I want to write the following: someNode.position = elementOfMarkArray.position
Use array's contains method
if (blueMarkArray.contains(self.atPoint(locationUser))) {
//
}
or, if you need to check only up to index 6 like in your example, use
if (blueMarkArray[0...6].contains(self.atPoint(locationUser))) {
//
}
if you want to get the index of the element, you can use firstIndex of lastIndex methods
if let index = blueMarkArray.firstIndex(of: self.atPoint(locationUser)) {
//
}
You can use the array's method contains:
if blueMarkArray.contains(self.atPoint(locationUser)) {
print("its here")
}
You should simply use the contains method of Array, which will return true if any of the elements of the array equals self.atPoint(locationUser).
if blueMarkArray.contains(self.atPoint(locationUser)) {
print("it's here")
}
If you also need to access the element that matches the object/value you are looking for, you can use first(where:) or firstIndex(of:).
if let location = blueMarkArray.first(where: {$0 == self.atPoint(locationUser)}) {
someNode.position = location.position
}
or
if let locationIndex = blueMarkArray.firstIndex(of: self.atPoint(locationUser)) {
let location = blueMarkArray[locationIndex]
someNode.position = location.position
}

Swift: "Where" vs "If"

Is there any difference between these two syntaxes? If not, any benefit?
if let userName = userNameTextField.text where userName.characters.count > 0,
let password = passwordTextField.text where password.characters.count > 0,
let confirmation = confirmationTextField.text where confirmation == password
else {
return false
}
and:
if userNameTextField.text?.characters.count > 0 &&
passwordTextField.text?.characters.count > 0 &&
confirmationTextField.text == passwordTextField.text
{
return false
}
First of all, note that where clauses in optional binding conditions is deprecated in Swift 3.0, replaced by ,.
Evolution Proposal SE-0099: Restructuring Condition Clauses
I.e.
let opt: Int?
/* Swift < 3 */
if let opt = opt where opt == 42 { /* ... */ }
/* Swift >= 3 */
if let opt = opt, opt == 42 { /* ... */ }
Secondly, your second example block wont compile in Swift >= 3.0, as the optional result from the optional chaining is not unwrapped; comparing optionals to literals has been removed in Swift 3.0 (thanks #MartinR), as per the following implemented proposals:
Evolution proposal SE-0121: Remove Optional Comparison Operators
Evolution proposal SE-0123: Disallow coercion to optionals in operator arguments
userNameTextField.text?.characters.count > 0 &&
/* ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
this is an optional that, for Swift >= 3.0, needs to be unwrapped
prior to comparing it to the integer literal */
Now, proceeding to answer your "is there any difference ..." question, assuming we look at your two options fixed for Swift 3.
You could choose to bind the value of the optional String property text of userNameTextField if you'd like to use it in the if block that follows, or
If youd only want to ascertain that the text property is not nil or empty (""), you could omit the binding in favour or simply checking its character.count
E.g.:
struct Foo {
var bar: String?
}
var foo = Foo()
/* if you want to use foo.bar within the if block */
if let str = foo.bar, str.characters.count > 0 {
// do something with str ...
print(str)
}
/* if you only need to ascertain foo.bar is not nil
and not empty */
if (foo.bar?.characters.count ?? 0) > 0 {
// do something with str ...
print("not empty")
}
// alternatively ... (not nil or empty)
if !(foo.bar?.isEmpty ?? true) {
// do something with str ...
print("not empty")
}
If you simply want to ascertain the latter and return false in case the ascertation fails, you could prefer using a guard statement instead of if:
guard (foo.bar?.characters.count ?? 0) > 0 else { return false }
// ... if no false return, proceed with app flow here ...
// alternatively ...
guard !(foo.bar?.isEmpty ?? true) else { return false }
Neither version works in Swift 3. And I think in the first version, you meant to use guard instead of let.
With Swift 3, you want to do the following:
guard
let userName = userNameTextField.text,
let password = passwordTextField.text,
let confirmation = confirmationTextField.text,
userName.characters.count > 0,
password.characters.count > 0,
confirmation == password
else {
return false
}
There are problems with using your approach in Swift 3 as explained by some of the other answers. But if you are using Swift 2, the following is my answer to your question.
The two are exactly the same with only one difference. Both approaches are testing for a nil value and then introducing a boolean test if the value is not nil. For example in your line,
if let userName = userNameTextField.text where userName.characters.count > 0
You are testing to see if userNameTextField is not nil and then you are testing if its count is greater than zero. The same thing applies this line,
if userNameTextField.text?.characters.count > 0
except it is much shorter and readable.
Because both approaches are within an 'if' statement, they both evaluate to true or false and achieve the same purpose.
However, what separates them is that with the 'where' clause, you can introduce a Boolean test after a binding or pattern, regardless of whether or not there's an underlying semantic link between the two. So I can basically do this with the 'where' clause,
if let userName = userNameTextField.text where age > 0
There is no semantic link between userNameTextField and age. As you can imagine, that might not be what you intended and this can quickly lead to errors.

I am trying to update my for loop for Swift 3 and I can't figure it out. I keep getting errors

This is my original function in Swift 2:
// check on winning combinations
func checkWinnerMove(){
for var i = 0; i<winningCombinations.count && !isWinner;i += 1 {
if gameState[winningCombinations[i][0]-1] == activePlayer &&
gameState[winningCombinations[i][1]-1] == activePlayer &&
gameState[winningCombinations[i][2]-1] == activePlayer{
isWinner = true;
}else{
isWinner = false;
}
}
}
I have changed it to this:
// check on winning combinations
func checkWinnerMove(){
for i in 0 ..< winningCombinations.count && !isWinner{
if gameState[winningCombinations[i][0]-1] == activePlayer &&
gameState[winningCombinations[i][1]-1] == activePlayer &&
gameState[winningCombinations[i][2]-1] == activePlayer{
isWinner = true;
}else{
isWinner = false;
}
}
}
But keep getting a error when I add the
&& !isWinner
statment in the for-in loop. The error I get is:
No '..<' candidates produce the expected contextual result type 'Bool'
Any suggestions? Thank You!
Instead of forcibly trying to rewrite your original C-style for loop, consider what you're trying to achieve and attempt to re-write it in "native" Swift from scratch. How about breaking out of your loop once your true condition is met, instead of keeping it in the loop signature? E.g.
for i in 1...5 {
print(i)
if i == 3 { break }
} // 1 2 3
Applied to your example
func checkWinnerMove()
isWinner = false
for i in 0 ..< winningCombinations.count {
if gameState[winningCombinations[i][0]-1] == activePlayer &&
gameState[winningCombinations[i][1]-1] == activePlayer &&
gameState[winningCombinations[i][2]-1] == activePlayer {
isWinner = true
break
}
}
}
The explicit by index access of the (unknown for us) gameState and winningCombinations sequences is quite "unswifty" w.r.t. in the dangers of runtime exceptions for indices out of range for the sequences. So bear in mind that there are safer ways to perform such access.
For future reference, consider reading How to create a Minimal, Complete, and Verifiable example: since we (the potential answerer's of your question) don't have access to/the full information regarding isWinner, winningCombinations, gameState or activePlayer, we can't verify your example. Also, since the question cover a concept, it could be boiled down to a more minimal form. (Welcome to StackOverflow!)

How can I check if a string contains letters in Swift? [duplicate]

This question already has answers here:
What is the best way to determine if a string contains a character from a set in Swift
(11 answers)
Closed 7 years ago.
I'm trying to check whether a specific string contains letters or not.
So far I've come across NSCharacterSet.letterCharacterSet() as a set of letters, but I'm having trouble checking whether a character in that set is in the given string. When I use this code, I get an error stating:
'Character' is not convertible to 'unichar'
For the following code:
for chr in input{
if letterSet.characterIsMember(chr){
return "Woah, chill out!"
}
}
You can use NSCharacterSet in the following way :
let letters = NSCharacterSet.letters
let phrase = "Test case"
let range = phrase.rangeOfCharacter(from: characterSet)
// range will be nil if no letters is found
if let test = range {
println("letters found")
}
else {
println("letters not found")
}
Or you can do this too :
func containsOnlyLetters(input: String) -> Bool {
for chr in input {
if (!(chr >= "a" && chr <= "z") && !(chr >= "A" && chr <= "Z") ) {
return false
}
}
return true
}
In Swift 2:
func containsOnlyLetters(input: String) -> Bool {
for chr in input.characters {
if (!(chr >= "a" && chr <= "z") && !(chr >= "A" && chr <= "Z") ) {
return false
}
}
return true
}
It's up to you, choose a way. I hope this help you.
You should use the Strings built in range functions with NSCharacterSet rather than roll your own solution. This will give you a lot more flexibility too (like case insensitive search if you so desire).
let str = "Hey this is a string"
let characterSet = NSCharacterSet(charactersInString: "aeiou")
if let _ = str.rangeOfCharacterFromSet(characterSet, options: .CaseInsensitiveSearch) {
println("true")
}
else {
println("false")
}
Substitute "aeiou" with whatever letters you're looking for.
A less flexible, but fun swift note all the same, is that you can use any of the functions available for Sequences. So you can do this:
contains("abc", "c")
This of course will only work for individual characters, and is not flexible and not recommended.
The trouble with .characterIsMember is that it takes a unichar (a typealias for UInt16).
If you iterate your input using the utf16 view of the string, it will work:
let set = NSCharacterSet.letterCharacterSet()
for chr in input.utf16 {
if set.characterIsMember(chr) {
println("\(chr) is a letter")
}
}
You can also skip the loop and use the contains algorithm if you only want to check for presence/non-presence:
if contains(input.utf16, { set.characterIsMember($0) }) {
println("contains letters")
}