How to compare to optional arrays? [duplicate] - swift

This question already has an answer here:
Why is Equatable not defined for optional arrays
(1 answer)
Closed 6 years ago.
I'd like a function to compare [String]? with [String]? where either, both or neither are nil. If both are nil then the function returns true
Is there notation where I can avoid checking a value is equal to nil?
This:
func compare_colours(a1:[String]?, a2:[String]?) -> Bool {
return a1 == a2
}
isn't valid in Swift because I'd need to add ! first:
return a1! == a2!

if let a1Unwrapped = a1{
if let a2Unwrapped = a2{
return a1Unwrapped == a2Unwrapped
}
}
if (a1 == nil && a2 == nil){
return true
}
return false

I prefer using guard over if statements so I can avoid the pyramid of doom:
func compare_colours(a1:[String]?, a2:[String]?) -> Bool {
if a1 == nil && a2 == nil { return true }
guard let unwrapped1 = a1 else { return false }
guard let unwrapped2 = a2 else { return false }
return unwrapped1 == unwrapped2
}
You don't need to check for nil. Instead you can check to see if the Optional enum is .None:
switch (a1, a2) {
case (.None, .None): print("Both unset Optional")
}
Either way you have to do the same basic thing, check for nil/.None. For more details on how this works you can read this answer: https://stackoverflow.com/a/33209762/887210

Or just use the optional as an empty and you can match all scenarios.
func compare_colours(a1:[String]?, a2:[String]?) -> Bool {
return a1 ?? [""] == a2 ?? [""]
}

Related

Enum pattern matching as a parameter to a function call

I've setup a playground with an example:
enum CarType : Equatable {
case wheeled(wheels: Int)
case flying
public static func ==(lhs: CarType, rhs: CarType) -> Bool {
return lhs.enumName == rhs.enumName
}
var enumName: String {
let stuff = "\(self)".split(separator: "(").first!
return String(describing: stuff)
}
}
var typesPresentAtMyParty = [CarType.wheeled(wheels:4), .wheeled(wheels:4), .flying]
let aKnownType = CarType.flying
if case aKnownType = typesPresentAtMyParty[2] {
print("Was the type")
}
func isPresent(type: CarType, inArray: [CarType]) -> Bool {
return inArray.filter {
if case type = $0 {
return true
}
return false
}.first != nil
}
func isWheeled(inArray: [CarType]) -> Bool {
return inArray.filter {
if case .wheeled = $0 {
return true
}
return false
}.first != nil
}
isPresent(type: .flying, inArray: typesPresentAtMyParty)
isPresent(type: .wheeled, inArray: typesPresentAtMyParty)
The last line here does not compile. While i can do if case .wheeled = $0 ignoring associated type as a check, i cannot find a way of doing the same in a function call isPresent(type: CarType, inArray: [CarType]), when sending isPresent(type: .wheeled, inArray: typesPresentAtMyParty)
Is there a way of writing a function that takes only the valid pattern matching part of the enum as a parameter?
It is not possible to pass partially constructed enums to a function. Partially constructed enums are not valid values, and they only work in pattern matching because the compiler has a concrete value to work with - the one from the right side of the pattern.
These being said, you could easily rewrite your functions to better, more swiftier versions.
Firstly, you don't need isPresent, you can simply use contains:
typesPresentAtMyParty.contains { $0 == .flying }
typesPresentAtMyParty.contains { if case . wheeled = $0 { return true } else { return false } }
Similarly, isWheeled can be shortened (and renamed, for better semantics):
func isWheeled(_ carType: CarType) -> Bool {
if case . wheeled = carType { return true } else { return false }
}
which can pe passed to contains:
let hasWeeled = typesPresentAtMyParty.contains(where: isWheeled)

swift affect value to inout generic variable

I want to simplify this piece of code with a T variable but could not succeed in compiling it. Hope could you give me the way.
here is the "duplicate" code I want to rewrite :
func getIntegerValue (listValues: [Any], numValueToRead: Int, readValue: inout Int) -> Bool {
if numValueToRead < 0 || numValueToRead >= listValues.count {
return false
}
let value = listValues [numValueToRead]
if type (of: value) == type(of: readValue) {
readValue = value as! Int
return true
} else {
return false
}
}
func getStringValue (listValues: [Any], numValueToRead: Int, readValue: inout String) -> Bool {
if numValueToRead < 0 || numValueToRead >= listValues.count {
return false
}
let value = listValues [numValueToRead]
if type (of: value) == type(of: readValue) {
readValue = value as! String
return true
} else {
return false
}
}
Here is the code I wrote but do not compile :
func getValue <T> (listValues: [Any], numValueToRead: Int, readValue: inout T) -> Bool {
if numValueToRead < 0 || numValueToRead >= listValues.count {
return false
}
let value = listValues [numValueToRead]
if type (of: value) == type(of: readValue) {
switch value {
case let integerValue as Int:
readValue = integerValue
case let stringValue as String:
readValue = stringValue
default:
return false
}
return true
} else {
return false
}
}
for those affectations I got those compilation errors :
readValue = integerValue -> 'Int' is not convertible to 'T'
readValue = stringValue -> 'String' is not convertible to 'T'
Is there a way to synthetise my two functions with a unique one using generics ?
You theoretically could make it compile by adding forced casts, since you already know that value has the type T:
case let integerValue as Int:
readValue = integerValue as! T
case let stringValue as String:
readValue = stringValue as! T
But the far better solution is to use a conditional cast (as? T) and
conditional binding (if let):
func getValue<T>(listValues: [Any], numValueToRead: Int, readValue: inout T) -> Bool {
if numValueToRead < 0 || numValueToRead >= listValues.count {
return false
}
let value = listValues[numValueToRead]
if let tvalue = value as? T {
readValue = tvalue
return true
} else {
return false
}
}
which then works for arbitrary types, not only Int and String.
A “swiftier” way would be return an optional value (with nil
indicating "no value"). The code can then be simplified to
func getValue<T>(listValues: [Any], numValueToRead: Int) -> T? {
guard listValues.indices.contains(numValueToRead) else {
return nil
}
return listValues[numValueToRead] as? T
}
This should work:
func getValue <T> (listValues: [Any], numValueToRead: Int, readValue: inout T) -> Bool {
if numValueToRead < 0 || numValueToRead >= listValues.count {
return false
}
let value = listValues [numValueToRead]
if type (of: value) == type(of: readValue) {
if let genericValue = value as? T {
readValue = genericValue
return true
}
return false
} else {
return false
}
}
At first sight, the function is wrongly named. You cannot call function getValue when it returns bool... I would call it transform or modify or something other than get value, because you are NOT getting value.
I think this method suits better your needs, not tested tought it should work.
func transformValue<T>(from listValues: [Any], numValueToRead: Int, readValue: inout T?) throws -> Bool {
// Guard suits better this case...
guard numValueToRead > 0 || numValueToRead < listValues.count else { return false }
let value = listValues[numValueToRead]
if type (of: value) == type(of: readValue) {
guard let value = value as? T else {
throw NSError(
domain: "Smth",
code: 1,
userInfo: ["Description": "Failed to cast to generic type T"]
)
}
readValue = value as? T
return true
}
return false // No need to call else...
}
Explenation: Returning optional generic type T is much safer. You try to cast it, you fail and you throw error that something went wrong. In my opinion saving force casts with throwing errors is much more safer approach, you know what went wrong and so.
As #MartinR pointed out, returning a nil value instead of an inout+Bool combination gives the same results, but with less, and more readable code. This is the path Swift also took when importing most of the NSError ** methods from Objective-C (i.e. dropped the last parameter, imported them as throwable functions).
These being said, another approach would be to add an extension over Array for extracting the value:
extension Array {
subscript<T>(_ index: Int, as type: T.Type) -> T? {
guard 0..<count ~= index else { return nil }
return self[index] as? T
}
}
let arr: [Any] = [1, "two", 3, "four"]
arr[1, as: String.self] // two
arr[2, as: String.self] // nil

Evaluating Swift's Bool? for true/false/nil in one line?

I've got a lot of code like this:
if let x = optbool {
return f(x)
} else {
return false
}
Can this be expressed on a single line?
The following statement is equivalent to your code:
return optbool.map(f) ?? false
If optbool == nil then .map(f) returns nil,
and the nil-coalescing operator ?? false changes that
to false.
If optbool != nil then .map(f) returns f(optbool!),
which is also the result of the nil-coalescing operator.
Try this:
return optbool != nil ? f(optbool!) : false
your code is valid only if func f(x:Bool)->Bool
func foo(b: Bool?)-> Bool {
if let x = b {
return f(x)
} else {
return false
}
}
now the question has no logic more ... and you can use one of this
let res1 = f(b ?? false)
let res2 = f(b ?? true)
let res3 = !f(b ?? false)
let res4 = !f(b ?? true)
depending on your f function
If you define the f function as an extension of Bool:
extension Bool {
func f() -> Bool {
return true // or false..
}
}
then you can write
return x?.f() ?? false
or
return x?.f() == true
If your question is really:
Can this be expressed on a single line?
The answer is undoubtedly YES:
if let x = optbool { return f(x) } else { return false }
;-)
Seriously, if optbool is not supposed to be nil, I would rather write it on 2 lines:
guard let x = optbool else { return false }
return f(x)

Check string for nil & empty

Is there a way to check strings for nil and "" in Swift? In Rails, I can use blank() to check.
I currently have this, but it seems overkill:
if stringA? != nil {
if !stringA!.isEmpty {
...blah blah
}
}
If you're dealing with optional Strings, this works:
(string ?? "").isEmpty
The ?? nil coalescing operator returns the left side if it's non-nil, otherwise it returns the right side.
You can also use it like this to return a default value:
(string ?? "").isEmpty ? "Default" : string!
You could perhaps use the if-let-where clause:
Swift 3:
if let string = string, !string.isEmpty {
/* string is not blank */
}
Swift 2:
if let string = string where !string.isEmpty {
/* string is not blank */
}
With Swift 5, you can implement an Optional extension for String type with a boolean property that returns if an optional string is empty or has no value:
extension Optional where Wrapped == String {
var isEmptyOrNil: Bool {
return self?.isEmpty ?? true
}
}
However, String implements isEmpty property by conforming to protocol Collection. Therefore we can replace the previous code's generic constraint (Wrapped == String) with a broader one (Wrapped: Collection) so that Array, Dictionary and Set also benefit our new isEmptyOrNil property:
extension Optional where Wrapped: Collection {
var isEmptyOrNil: Bool {
return self?.isEmpty ?? true
}
}
Usage with Strings:
let optionalString: String? = nil
print(optionalString.isEmptyOrNil) // prints: true
let optionalString: String? = ""
print(optionalString.isEmptyOrNil) // prints: true
let optionalString: String? = "Hello"
print(optionalString.isEmptyOrNil) // prints: false
Usage with Arrays:
let optionalArray: Array<Int>? = nil
print(optionalArray.isEmptyOrNil) // prints: true
let optionalArray: Array<Int>? = []
print(optionalArray.isEmptyOrNil) // prints: true
let optionalArray: Array<Int>? = [10, 22, 3]
print(optionalArray.isEmptyOrNil) // prints: false
Sources:
swiftbysundell.com - Extending optionals in Swift
objc.io - Swift Tip: Non-Empty Collections
Using the guard statement
I was using Swift for a while before I learned about the guard statement. Now I am a big fan. It is used similarly to the if statement, but it allows for early return and just makes for much cleaner code in general.
To use guard when checking to make sure that a string is neither nil nor empty, you can do the following:
let myOptionalString: String? = nil
guard let myString = myOptionalString, !myString.isEmpty else {
print("String is nil or empty.")
return // or break, continue, throw
}
/// myString is neither nil nor empty (if this point is reached)
print(myString)
This unwraps the optional string and checks that it isn't empty all at once. If it is nil (or empty), then you return from your function (or loop) immediately and everything after it is ignored. But if the guard statement passes, then you can safely use your unwrapped string.
See Also
Statements documentation
The Guard Statement in Swift 2
If you are using Swift 2, here is an example my colleague came up with, which adds isNilOrEmpty property on optional Strings:
protocol OptionalString {}
extension String: OptionalString {}
extension Optional where Wrapped: OptionalString {
var isNilOrEmpty: Bool {
return ((self as? String) ?? "").isEmpty
}
}
You can then use isNilOrEmpty on the optional string itself
func testNilOrEmpty() {
let nilString:String? = nil
XCTAssertTrue(nilString.isNilOrEmpty)
let emptyString:String? = ""
XCTAssertTrue(emptyString.isNilOrEmpty)
let someText:String? = "lorem"
XCTAssertFalse(someText.isNilOrEmpty)
}
var str: String? = nil
if str?.isEmpty ?? true {
print("str is nil or empty")
}
str = ""
if str?.isEmpty ?? true {
print("str is nil or empty")
}
I know there are a lot of answers to this question, but none of them seems to be as convenient as this (in my opinion) to validate UITextField data, which is one of the most common cases for using it:
extension Optional where Wrapped == String {
var isNilOrEmpty: Bool {
return self?.trimmingCharacters(in: .whitespaces).isEmpty ?? true
}
}
You can just use
textField.text.isNilOrEmpty
You can also skip the .trimmingCharacters(in:.whitespaces) if you don't consider whitespaces as an empty string or use it for more complex input tests like
var isValidInput: Bool {
return !isNilOrEmpty && self!.trimmingCharacters(in: .whitespaces).characters.count >= MIN_CHARS
}
If you want to access the string as a non-optional, you should use Ryan's Answer, but if you only care about the non-emptiness of the string, my preferred shorthand for this is
if stringA?.isEmpty == false {
...blah blah
}
Since == works fine with optional booleans, I think this leaves the code readable without obscuring the original intention.
If you want to check the opposite: if the string is nil or "", I prefer to check both cases explicitly to show the correct intention:
if stringA == nil || stringA?.isEmpty == true {
...blah blah
}
I would recommend.
if stringA.map(isEmpty) == false {
println("blah blah")
}
map applies the function argument if the optional is .Some.
The playground capture also shows another possibility with the new Swift 1.2 if let optional binding.
SWIFT 3
extension Optional where Wrapped == String {
/// Checks to see whether the optional string is nil or empty ("")
public var isNilOrEmpty: Bool {
if let text = self, !text.isEmpty { return false }
return true
}
}
Use like this on optional string:
if myString.isNilOrEmpty { print("Crap, how'd this happen?") }
Swift 3
For check Empty String best way
if !string.isEmpty{
// do stuff
}
Swift 3 solution
Use the optional unwrapped value and check against the boolean.
if (string?.isempty == true) {
// Perform action
}
You should do something like this:
if !(string?.isEmpty ?? true) { //Not nil nor empty }
Nil coalescing operator checks if the optional is not nil, in case it is not nil it then checks its property, in this case isEmpty. Because this optional can be nil you provide a default value which will be used when your optional is nil.
Based on this Medium post, with a little tweak for Swift 5, I got to this code that worked.
if let stringA, !stringA.isEmpty {
...blah blah
}
Although I understand the benefits of creating an extension, I thought it might help someone needing just for a small component / package.
You can create your own custom function, if that is something you expect to do a lot.
func isBlank (optionalString :String?) -> Bool {
if let string = optionalString {
return string.isEmpty
} else {
return true
}
}
var optionalString :String? = nil
if isBlank(optionalString) {
println("here")
}
else {
println("there")
}
Create a String class extension:
extension String
{ // returns false if passed string is nil or empty
static func isNilOrEmpty(_ string:String?) -> Bool
{ if string == nil { return true }
return string!.isEmpty
}
}// extension: String
Notice this will return TRUE if the string contains one or more blanks. To treat blank string as "empty", use...
return string!.trimmingCharacters(in: CharacterSet.whitespaces).isEmpty
... instead. This requires Foundation.
Use it thus...
if String.isNilOrEmpty("hello world") == true
{ print("it's a string!")
}
Swift 3
This works well to check if the string is really empty. Because isEmpty returns true when there's a whitespace.
extension String {
func isEmptyAndContainsNoWhitespace() -> Bool {
guard self.isEmpty, self.trimmingCharacters(in: .whitespaces).isEmpty
else {
return false
}
return true
}
}
Examples:
let myString = "My String"
myString.isEmptyAndContainsNoWhitespace() // returns false
let myString = ""
myString.isEmptyAndContainsNoWhitespace() // returns true
let myString = " "
myString.isEmptyAndContainsNoWhitespace() // returns false
Using isEmpty
"Hello".isEmpty // false
"".isEmpty // true
Using allSatisfy
extension String {
var isBlank: Bool {
return allSatisfy({ $0.isWhitespace })
}
}
"Hello".isBlank // false
"".isBlank // true
Using optional String
extension Optional where Wrapped == String {
var isBlank: Bool {
return self?.isBlank ?? true
}
}
var title: String? = nil
title.isBlank // true
title = ""
title.isBlank // true
Reference : https://useyourloaf.com/blog/empty-strings-in-swift/
This is a general solution for all types that conform to the Collection protocol, which includes String:
extension Optional where Wrapped: Collection {
var isNilOrEmpty: Bool {
self?.isEmpty ?? true
}
}
When dealing with passing values from local db to server and vice versa, I was having too much trouble with ?'s and !'s and what not.
So I made a Swift3.0 utility to handle null cases and i can almost totally avoid ?'s and !'s in the code.
func str(_ string: String?) -> String {
return (string != nil ? string! : "")
}
Ex:-
Before :
let myDictionary: [String: String] =
["title": (dbObject?.title != nil ? dbObject?.title! : "")]
After :
let myDictionary: [String: String] =
["title": str(dbObject.title)]
and when its required to check for a valid string,
if !str(dbObject.title).isEmpty {
//do stuff
}
This saved me having to go through the trouble of adding and removing numerous ?'s and !'s after writing code that reasonably make sense.
Use the ternary operator (also known as the conditional operator, C++ forever!):
if stringA != nil ? stringA!.isEmpty == false : false { /* ... */ }
The stringA! force-unwrapping happens only when stringA != nil, so it is safe. The == false verbosity is somewhat more readable than yet another exclamation mark in !(stringA!.isEmpty).
I personally prefer a slightly different form:
if stringA == nil ? false : stringA!.isEmpty == false { /* ... */ }
In the statement above, it is immediately very clear that the entire if block does not execute when a variable is nil.
helpful when getting value from UITextField and checking for nil & empty string
#IBOutlet weak var myTextField: UITextField!
Heres your function (when you tap on a button) that gets string from UITextField and does some other stuff
#IBAction func getStringFrom_myTextField(_ sender: Any) {
guard let string = myTextField.text, !(myTextField.text?.isEmpty)! else { return }
//use "string" to do your stuff.
}
This will take care of nil value as well as empty string.
It worked perfectly well for me.
Swift 5.6 - Xcode 13
extension Optional where Wrapped: Collection {
var isEmptyOrNil: Bool {
guard let self = self else { return true }
return self.isEmpty
}
}
Usage:
var name: String?
if name.isEmptyOrNil {
///true
}
name = "John Peter"
guard !name.isEmptyOrNil else { return }
/// Name is not empty
you can use this func
class func stringIsNilOrEmpty(aString: String) -> Bool { return (aString).isEmpty }

Why does this work (not using vs. using optionals)?

Why does alternative1 below work flawlessly?
The macros are bogus of course and for illustration purposes only:
func commonPrefixLength<T: Swift.Collection, U: Swift.Collection where
T: Sequence, U: Sequence,
T.GeneratorType.Element: Equatable,
T.GeneratorType.Element == U.GeneratorType.Element>
(collection1: T, collection2: U) -> T.IndexType.DistanceType {
var collection2generator = collection2.generate()
var i: T.IndexType.DistanceType = 0
for element1 in collection1 {
#if alternative1
let element2 = collection2generator.next()
if (element1 != element2) {
return i
}
#elseif alternative2
let optionalElement2 = collection2generator.next()
if let element2 = optionalElement2 {
if (element1 != element2) {
return i
}
}
else {
break
}
#endif
i++
}
return i
}
commonPrefixLength("abX", "abc")
Here is a gist of the above.
In the comparison, you are comparing an optional (element2) with an non-optional (element1).
if (element1 != element2) {
return i
}
There is no problem comparing an optional to an non-optional. Why should there be? If element2 is nil, then the result of the above comparison will be true. That's well defined.
Non-optionals can be implicitly cast to optionals, otherwise you wouldn't be able to assign a non-optional to an optional.
let nonOptional = ""
var optional: String? = nonOptional