This question already has answers here:
Swift switch pattern matching with arrays
(3 answers)
Closed 6 years ago.
I want to put my array of values as a case for my switch statement
I have an array of values say
let intValues = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20 .... 100]
and I want to use a switch statement to be used as a comparison tool like so.
let inputValue = 30 // or some other int value
switch inputValue {
case 101:
// do something lol
/* =============================== */
case intValues: //
// do something more:
/* =============================== */
case 13131:
// do another thing
default:
// do default
}
I know I can do this easily by either doing this case 1, 2, 3, 4, 5, and so on or by using an if statement like so:
if intValues.contains(inputValue) {
// do something more:
} else if inputValue == 101 {
// do something lol
} else if inputValue == 13131 {
// do another thing
} else {
// do default
}
or by doing somethig like
if intValues.contains(inputValue) {
// do something more:
} else {
switch inputValue {
case 101:
// do something lol
case 13131:
// do another thing
default:
// do default
}
}
and vice versa
But is it possible though? to do it with just a switch statement?
You can use case let with where for that.
let intValues = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20]
let inputValue = 30 // or some other int value
switch inputValue {
case let x where intValues.contains(x):
// do something more:
case 101:
// do something lol
case 13131:
// do another thing
default:
// do default
}
You can do this with range operator.
let inputValue = 30
switch value {
case 1...100:
print("between hundred")
case 101:
print("it's 101")
default:
print("outer value")
}
You should just use a countable closed range in your switch cases:
let inputValue = 30
switch inputValue {
case 1...10:
print(1...10)
case 11...20:
print(11...20)
case 21...100:
print(21...100) // "21...100\n"
default:
print("default")
}
Related
When I have a situation where I already know enum case statement I want to get the associated value of, is there a cleaner way than using a switch statement to pluck out the associated value?
To have to come up with a switch statement, provide multiple cases, or a default case just to extract the associated value is gaudy.
enum CircularReasoning {
case justPi(pi: Double)
case pizzaPie(howMany: Int)
}
var piInTheSky : Double
let whatLogic = CircularReasoning(pi: 3.1415926)
β¬οΈ πΈπ’π―π΅ π΅π° π’π·π°πͺπ₯ β¬οΈ
switch whatLogic {
case .justPi(let pi):
piInTheSky = pi!
default:
break
}
You can use if case .<enum_case>(let value) as in TylerP's example,
or if case let .<enum_case>(value):
enum Foo {
case anInt(Int)
case aFloat(Float)
}
let aFoo: Foo = .anInt(9)
// Example of `if case .<enum_case)(let value)` syntax:
if case .anInt(let aValue) = aFoo {
print("aFoo = anInt(\(aValue))")
// Example of `if case let .enum_case(value)` syntax:
} else if case let .aFloat(aValue) = aFoo {
print("aFoo = aFloat(\(aValue))")
}
Both work. I'm not sure why the language includes both variants.
If you only care about one enum type, then either if syntax makes sense to me. If you are dealing with more than one possible enum value then the switch version seems cleaner.
Here's an adaptation of #DuncanC's excellent upvoted and accepted answer, as applied to a fictitious version of my real-world use case.
It illustrates a possible way to use his answer to reduce the space required to extract associated values, especially if one has a lot of one-off cases...
Note: Not implying this is appropriate or professional swift styling; it's clearly idiosyncratic, yet compact. (I usually don't compress things into one liners like this, unless they get really repetitive/redundant & produce lot of pointless vertical bloat).
enum RealmKey { case realmOfRealms, anyOldRealm, someOtherRealm }
.
.
.
enum SymbolToken {
case realm (key: RealmKey?)
case space (key: SpaceKey?)
case area (key: AreaKey?)
case region (key: RegionKey?)
case preserve (key: PeserveKey?)
case openParen
case closeParen
case logicalAnd
case logicalOr
case logicalNot
var realmKey : RealmKey? { if case .realm (let key) = self { return key } else { return nil } }
var spaceKey : SpaceKey? { if case .space (let key) = self { return key } else { return nil } }
var areaKey : AreaKey? { if case .area (let key) = self { return key } else { return nil } }
var regionKey : RegionKey? { if case .region (let key) = self { return key } else { return nil } }
var preserveKey : PreserveKey? { if case .preserve (let key) = self { return key } else { return nil } }
}
let realm = SymbolToken.realm(.realmOfRealms)
let realmKey = realm.realmKey
I'm rewriting a code from java to swift and need to break a multi-layered switches right way. In Java it looks like :
block0 : switch (topSwithch) {
case one: {
switch (innerSwitch) {
case insideCase: {
if (something){
break block0;
}
// etc
So, I'm breaking one switch from another. How do I do it in swift ?
This is what it'd look like in Swift. I did this in a playground with hardcoded values for the variables:
let topSwitch = 1
let innerSwitch = 4
let one = 1
let insideCase = 4
let something = true
block0 : switch (topSwitch) { //first switch labeled "block0", switching on topSwitch
case one: //topSwitch is 1, one is 1
switch (innerSwitch) { // switching on innerSwitch
case insideCase: // both are 1
if (something){ // if true
break block0; // break from "block0"
}
default: break // else
}
default: break // else
}
this is my code:
enum SymptomPeriod {
case Day
case Night
}
enum SymptomType {
case Breathing(SymptomPeriod)
case Breathlessness(SymptomPeriod)
case Opression(SymptomPeriod)
case Cough(SymptomPeriod)
case ActivityLimited()
case SecureTreatment()
}
struct Symptom {
let type: SymptomType
let date: NSDate
}
And i have an array of symptoms.
let symptomList: [Symptom] = ...
My need is to filter the list of symptoms with the SymptomPerion criteria, i trying to do like this:
let daySymtoms = symptomList.filter { (symptom) -> Bool in
return symptom.type = ???
}
My problem is in the filter function.
(My goal is to use a filter function and not a loop)
A few suggestions
Use your struct as namespace
Instead of repeating the word Symptom (e.g. SymptomPeriod, SymptomType) you should put your enums into you Symptom struct
Rename SymptomType as Kind
Once you moved SymptomType into Symptom you can drop the Symptom part of the name. However using Type as name will create a conflict so you should rename it Kind.
Add the period computed property to Kind
This will make the filtering much easier
Here's the code
struct Symptom {
enum Period {
case Day
case Night
}
enum Kind {
case Breathing(Period)
case Breathlessness(Period)
case Opression(Period)
case Cough(Period)
case ActivityLimited()
case SecureTreatment()
var period: Period? {
switch self {
case Breathing(let period): return period
case Breathlessness(let period): return period
case Opression(let period): return period
case Cough(let period): return period
default: return nil
}
}
}
let kind: Kind
let date: NSDate
}
The solution
Now the filtering has become very easy
let symptoms: [Symptom] = ...
let filtered = symptoms.filter { $0.kind.period == .Day }
This is how i am doing it:
let daySymtoms = symtoms.filter { (symptom) -> Bool in
switch symptom.type {
case .Breathing(.Day), .Breathlessness(.Day), .Opression(.Day), .Cough(.Day):
return true
default:
return false
}
}
Let me know if you have more simple way to do it.
Given the following enum:
enum GameLevel {
case Level(Int)
case TutorialLevel, BossLevel
}
How to generate a random variable of type GameLevel in Swift?
I updated your enum as per Apple standards (Capital letter to start a Type, and no abbreviations.
enum GameLevel {
case Level(Int)
case TutorialLevel, BossLevel
}
First, how to create a constant or variable with a value for level.
let level = GameLevel.Level(1)
Next, for a random value to level use arc4random_uniform:
let maxGameLevel: UInt32 = 10
let randomGameLevel: Int = Int(arc4random_uniform(maxGameLevel))
let level = GameLevel.Level(randomGameLevel)
Of course, this can be put into a function:
func RandomGameLevel() -> GameLevel {
let maxGameLevel: UInt32 = 10
return .Level(Int(arc4random_uniform(maxGameLevel)))
}
let level = RandomGameLevel()
Finally, here is how you would use it in a case statement:
switch level {
case .Level(let levelValue):
println("Level \(levelValue)")
case .TutorialLevel:
println("Tutorial Level")
case .BossLevel:
println("Boss Level")
}
Update
OK, it's not too hard to include the other values. I'll also put all of this into GameLevel to package it up better.
enum GameLevel {
case Level(Int)
case TutorialLevel, BossLevel
static func Random() -> GameLevel {
let maxGameLevel: UInt32 = 10 /* levels will be 0 through 9 */
let otherGameLevels: UInt32 = 2 /* TutorialLevel and BossLevel */
let levelValue = Int(arc4random_uniform(maxGameLevel + otherGameLevels))
switch levelValue {
case 10: return .TutorialLevel
case 11: return .BossLevel
default: return .Level(levelValue)
}
}
}
Then
let level = GameLevel.Random()
Not the cleanest, but it's a start.
enum GameLevel: CaseIterable {
case Level(Int)
case TutorialLevel, BossLevel
}
let level:GameLevel = GameLevel.allCases.randomElement()!
Why would you need it that way? :(
Assign numbers to your start and final levels and implement a function, which will return random in that range as Lvl(int)
I want to have a constant using let that may be one of several values.
For instance:
if condition1 {
constant = "hi"
}
else if condition2 {
constant = "hello"
}
else if condition3 {
constant = "hey"
}
else if condition4 {
constant = "greetings"
}
I'm not sure how to do this with Swift and the let feature. But I'm inclined to believe it's possible, as this is in the Swift book:
Use let to make a constant and var to make a variable. The value of a constant doesnβt need to be known at compile time, but you must assign it a value exactly once.
How would I accomplish this?
As pointed out in the other answers you can't directly do this. But if you're looking to just variably set the initial value of a constant, then yes, that is possible. Here's an example with a computed property.
class MyClass {
let aConstant: String = {
if something == true {
return "something"
} else {
return "something else"
}
}()
}
I think you are looking for variable which will be assigned later inside switch-case:
let constant :String
switch conditions {
case condition1:
constant = "hi"
case condition2:
constant = "hello"
case condition3:
constant = "hey"
case condition4:
constant = "greetings"
default:
constant = "salute"
}
One option would be something like this, using a closure:
let constant: String = ({ value in
if conditionOne {
return "Hi"
} else if conditionTwo {
return "Bye"
}
return "Oops!"
})(myData /*needed for condition*/)
Or, for another twist, using generics:
func fancySwitch<S, T>(val: S, fn: S -> T) -> T {
return fn(val)
}
let x: String = fancySwitch(3) { val in
if val == 2 {
return "Hi"
} else if val < 5 {
return "Bye"
}
return "Oops"
}
let y: String = fancySwitch((3, 4)) { (a, b) in
if a == 2 {
return "Hi"
} else if b < 5 {
return "Bye"
}
return "Oops"
}
I understand what you're looking for. In Scala and some other functional languages this can be done using the match statement (kind of like switch) because the entire statement resolves to a value like this:
val b = true
val num = b match {
case true => 1
case false => 0
}
This is unfortunately not directly possible in Swift because there is no way to get a value from a branch statement. As stated in the Swift book, "Swift has two branch statements: an if statement and a switch statement." Neither of these statements resolve to a value.
The closest code structure I can think of is to first use a variable to retrieve the correct value and then assign it to a constant to be used in any later code:
let b = true
var num_mutable: Int
switch b {
case true:
num_mutable = 1
default:
num_mutable = 0
}
let num = num_mutable
Just add the line let constant: String before your if/else statement.
Below, an excerpt from Swift 1.2 and Xcode 6.3 beta - Swift Blog - Apple Developer elaborates.
let constants are now more powerful and consistent β The new rule is
that a let constant must be initialized before use (like a var), and
that it may only be initialized, not reassigned or mutated after
initialization. This enables patterns like:
let x : SomeThing
if condition {
x = foo()
} else {
x = bar()
}
use(x)
This formerly required the use of a var even though there is no
mutation taking place. Properties have been folded into this model to
simplify their semantics in initializers as well.
I found the Swift blog post above from the article "Let It Go: Late Initialization of Let in Swift", which I found by googling: swift let constant conditional initialize.