John Doah
John Doah

Reputation: 1999

Switch case with range

I'm learning Swift and tried to program the game "Bullseye" from Ryan Wenderlich by my own before watching the videos.

I needed to give the user points depending on how close to the target number he was. I tried to calculate the difference and than check the range and give the user the points, This is what I did with If-else (Couldn't do it with switch case):

private func calculateUserScore() -> Int {
    let diff = abs(randomNumber - Int(bullsEyeSlider.value))
    if diff == 0 {
        return PointsAward.bullseye.rawValue
    } else if diff < 10 {
        return PointsAward.almostBullseye.rawValue
    } else if diff < 30 {
        return PointsAward.close.rawValue
    }
    return 0 // User is not getting points. 
}

Is there a way to do it more elegantly or with Switch-Case? I couldn't just do diff == 0 for example in the case in switch case as xCode give me an error message.

Upvotes: 43

Views: 38019

Answers (6)

Alejandro L.Rocha
Alejandro L.Rocha

Reputation: 1145

In case that you need to check if a value is bigger than any number or between 2 values use it is possible to use where instead of if looks a bit cleaner this will work

func isOutdated(days: Int) -> Outdated {

    var outdatedStatus = Outdated.none

    switch days {
    case _ where days < 5:
        outdatedStatus = .tooLow
    case 5...10:
        outdatedStatus = .low
    case 11...20:
        outdatedStatus = .high
    case _ where days > 20:
        outdatedStatus = .expired
    default:
        outdatedStatus = .none
    }
    return outdatedStatus
}

After the release of the new capabilities of Swift 5.9 this could be changed to something simpler:

func isOutdated(days: Int) -> Outdated {
    switch days {
    case _ where days < 5:
        .tooLow
    case 5...10:
        .low
    case 11...20:
        .high
    case _ where days > 20:
         .expired
    default:
         .none
    }
}

Upvotes: 17

iOSer
iOSer

Reputation: 2336

You can return the values you want accordingly:

switch diff {
case 0:
    print("Bull Eye")
case 1..<10:
    print("Almost Bull Eye")
case 10..<30:
    print("Close")
default:
    print("Too Far")
}

Upvotes: 9

Pratheesh Bennet
Pratheesh Bennet

Reputation: 171

In my case the compiler took CGFloat as a closed range of double, so I had to explicitly tell compiler that I am checking CGFloat range.

   var progress: CGFloat!
   switch CGFloat(progress) {
    case 0 ... 0.25:
        barColor = .red
    case 0.25 ... 0.5:
        barColor = .yellow
    default:
        break
    }

Upvotes: 1

Rakesha Shastri
Rakesha Shastri

Reputation: 11242

This should work.

private func calculateUserScore() -> Int {
    let diff = abs(randomNumber - Int(bullsEyeSlider.value))
    switch diff {
    case 0:
        return PointsAward.bullseye.rawValue
    case 1..<10:
        return PointsAward.almostBullseye.rawValue
    case 10..<30:
        return PointsAward.close.rawValue
    default:
        return 0
    }
}

It's there in the The Swift Programming Language book under Control Flow -> Interval Matching.

Upvotes: 82

Ankit Jayaswal
Ankit Jayaswal

Reputation: 5679

You have to use range-operators as case in switch-statement:

a...b // It have range from a to b, means b is included as well

a..<b // It have range from a to b-1, means b is not included

private func calculateUserScore() -> Int {
    let diff = abs(randomNumber - Int(bullsEyeSlider.value))
    switch diff {
    case 0: return PointsAward.bullseye.rawValue
    case 1..<10: return PointsAward.almostBullseye.rawValue
    case 10..<30: return PointsAward.close.rawValue
    default: return 0
    }
}

Upvotes: 4

Vitaliy Rusinov
Vitaliy Rusinov

Reputation: 266

Only for you:

enum PointsAward: Int {
    case close
    case almostBullseye
    case bullseye
}

private func calculateUserStory() -> Int {
    let bullsEyeSliderValue = 9
    let randomNumber = 100
    let diff = abs(randomNumber - Int(bullsEyeSliderValue))
    switch diff {
    case 0:
        return PointsAward.bullseye.rawValue
    case 0..<10:
        return PointsAward.almostBullseye.rawValue
    case 0..<30:
        return PointsAward.close.rawValue
    default: return 0
    }
}

Upvotes: 7

Related Questions