49

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.

pkamb
  • 33,281
  • 23
  • 160
  • 191
ICanCYou
  • 545
  • 1
  • 5
  • 8

8 Answers8

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

valuesArray.contains(str) // -> Bool
Aaron
  • 6,466
  • 7
  • 37
  • 75
21

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/

pkamb
  • 33,281
  • 23
  • 160
  • 191
Pat Niemeyer
  • 5,930
  • 1
  • 31
  • 35
  • 1
    Other than getting a missing label error for "other:", this worked perfectly for me to check a set of enum values. I suggest, if you are still around and see this, editing the code to add an underscore before the "other:" label or add the label to the oneOf() call. – David Rector Apr 17 '23 at 23:55
8

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

let validStrings = Set(["ab", "bc", "cd"])
if validStrings.contains(str) {
    //do something      
}
pkamb
  • 33,281
  • 23
  • 160
  • 191
Luke De Feo
  • 2,025
  • 3
  • 22
  • 40
  • really nice. I had really forgotten this feature. Glad you reminded me that.It's actually good you are making it a set just in case to avoid duplication :) have a nice day – Korpel Sep 23 '15 at 23:46
7

Use a Switch Statement.

switch stringValue {
case "ab", "bc", "cd":
    print("Yay!")
default:
    break     
}
pkamb
  • 33,281
  • 23
  • 160
  • 191
Dominic Smith
  • 632
  • 7
  • 12
3

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
}
pkamb
  • 33,281
  • 23
  • 160
  • 191
1
if someArray.contains(object) {
  // contains
} else {
  // does not contains
}

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

pkamb
  • 33,281
  • 23
  • 160
  • 191
Narendra G
  • 491
  • 4
  • 9
1

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.

Cristik
  • 30,989
  • 25
  • 91
  • 127
-9
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")
}
Donald Duck
  • 8,409
  • 22
  • 75
  • 99
Ankit Kushwah
  • 539
  • 4
  • 16
  • 2
    While this code snippet may be the solution, [including an explanation](https://meta.stackexchange.com/questions/114762/explaining-entirely-%E2%80%8C%E2%80%8Bcode-based-answers) really helps to improve the quality of your post. Remember that you are answering the question for readers in the future, and those people might not know the reasons for your code suggestion. – Narendra Jadhav Aug 03 '18 at 14:31
  • 4
    This is not the solution. Your solution checks if all the strings are equal. The question asks a way to evaluate to true if any one of them is equal. Change or remove. – Dhruv Sangvikar Aug 15 '18 at 16:33