ICanCYou
ICanCYou

Reputation: 555

How to compare one value against multiple values in Swift?

Let's say that you have the code

if stringValue == "ab" || stringValue == "bc" || stringValue == "cd" {
    // do something
}

Is there a way to shorten this condition or beautify it (preferably without using the switch statement)? I know that this code does NOT work:

if stringValue == ("ab" || "bc" || "cd") {
    // do something
}

I've seen some complex solutions on other languages, but they seem language specific and not applicable to Swift. Any solutions would be appreciated.

Upvotes: 50

Views: 23782

Answers (8)

Luke De Feo
Luke De Feo

Reputation: 2165

Not that I am aware; you can do something like this though:

let validStrings = Set(["ab", "bc", "cd"])
if validStrings.contains(str) {
    //do something      
}

Upvotes: 8

Pat Niemeyer
Pat Niemeyer

Reputation: 6388

You can create an extension like this:

extension Equatable {
    func oneOf(_ other: Self...) -> Bool {
        return other.contains(self)
    }
}

and use it like this:

if stringValue.oneOf("ab", "bc", "cd") { ... }

Credit for the impl which saved me typing it: https://gist.github.com/daehn/73b6a08b062c81d8c74467c131f78b55/

Upvotes: 21

Cristik
Cristik

Reputation: 32814

Just for fun, how about overloading functions over String:

if a.isOneOf("ab", "bc", "cd") {
    print("yes")
}

extension String {
    @inlinable
    func isOneOf(_ first: String, _ second: String) -> Bool {
        self == first || self == second
    }
    
    @inlinable
    func isOneOf(_ first: String, _ second: String, _ third: String) -> Bool {
        self == first || isOneOf(second, third)
    }
    
    @inlinable
    func isOneOf(_ first: String, _ second: String, _ third: String, _ fourth: String) -> Bool {
        self == first || isOneOf(second, third, fourth)
    }
}

This gives you full performance benefits, as the compiler will be able to inline and tail call as much as it wants, at the cost of having to write as many overloads as you need in your code, and also not being able to pass arrays - but other answers deal with this too.

Upvotes: 1

pkamb
pkamb

Reputation: 34983

The construction ["some", "array"].contains("value") works, but is somewhat annoying:

  1. It inverts the left-to-right order you may want to write.
  2. Items in the array are not declared using Swift's type inference, often forcing you to include unnecessary information to please the compiler.

You can instead use Set(["value"]).isSubset(of: ["some", "array"]).

The benefit is especially apparent when working with enums:

enum SomeReallyReallyLongTypeName {
    case one, two
}

struct Thing {
    let value: SomeReallyReallyLongTypeName
}
    
let thing = Thing(value: .one)



if Set([thing.value]).isSubset(of: [.one, .two]){
    // :)
    // Left-to-right order
    // You get nice type inference
}

if [SomeReallyReallyLongTypeName.one, .two].contains(thing.value) {
    // :(
    // Annoying to have "SomeReallyReallyLongTypeName" in the code
}

Upvotes: 3

Dominic Smith
Dominic Smith

Reputation: 662

Use a Switch Statement.

switch stringValue {
case "ab", "bc", "cd":
    print("Yay!")
default:
    break     
}

Upvotes: 7

Narendra G
Narendra G

Reputation: 549

if someArray.contains(object) {
  // contains
} else {
  // does not contains
}

The above function returns bool value, then you write logic accordingly.

Upvotes: 1

Ankit Kushwah
Ankit Kushwah

Reputation: 547

let a = 1
let b = 1
let c = 1
let d = 1
if a == b,a==c,a==d  {
    print("all of them are equal")
}
else {
    print("not equal")
}

Upvotes: -10

Aaron
Aaron

Reputation: 6704

let valuesArray = ["ab","bc","cd"]

valuesArray.contains(str) // -> Bool

Upvotes: 48

Related Questions