Swift switch statement on a tuple of optional booleans - switch-statement

I'm having trouble figuring out how to use optionals inside a tuple inside a switch. The below .Some(let ...) ... syntax works as non-tuple, but inside a tuple I get expected separator stuff :(
var dict = Dictionary<String,Bool>()
dict["a"] = true
switch (dict["a"],dict["b") {
case (.Some(let a) where !a, .Some(let b) where b):
println("false/nil, true")
case (.Some(let a) where a, .Some(let b) where !b):
println("true, false/nil")
I want to avoid doing the following
if let a = self.beaconList["a"] {
if let b = self.beaconList["b"] {
// a, b
} else {
// a, !b
}
} else {
if let b = self.beaconList["b"] {
// !a, b
} else {
// !a, !b
}
}

There are a bunch of ways to do this, but to fix the syntax of what you are trying to do literally, you need to explicitly unbox the Optional, either by matching against .Some(false), or unwrapping it with ! (which I think is kind of weird, as you'll see)
var dict = Dictionary<String,Bool>()
dict["a"] = true
dict["c"] = false
func matchOneOrTheOtherWithOptionals(a: Bool?, b: Bool?) -> String {
switch (a, b) {
case (.Some(true), let b) where b == .None || !b!: // gross
return "a was true, but b was None or false"
case (let a, .Some(true)) where a == .None || a == .Some(false):
return "a was None or false and b was true"
default:
return "They both had a value, or they were both missing a value"
}
}
matchOneOrTheOtherWithOptionals(true, .None) // "a was true, but b was None or false"
matchOneOrTheOtherWithOptionals(true, false) // "a was true, but b was None or false"
matchOneOrTheOtherWithOptionals(.None, true) // "a was None or false and b was true"
matchOneOrTheOtherWithOptionals(false, true) // "a was None or false and b was true"
matchOneOrTheOtherWithOptionals(false, false) // "They both had a value, or they were both missing a value"
matchOneOrTheOtherWithOptionals(true, true) // "They both had a value, or they were both missing a value"
matchOneOrTheOtherWithOptionals(.None, .None) // "They both had a value, or they were both missing a value"
You could also try the following:
func noneToFalse(bool: Bool?) -> Bool {
if let b = bool {
return b
} else {
return false
}
}
func matchOneOrTheOther(a: Bool, b: Bool) -> String {
switch (a, b) {
case (true, false):
return "a is true, b was false or None"
case (false, true):
return "a was false/None, b was true"
default:
return "both were true, or both were false/None"
}
}
matchOneOrTheOther(noneToFalse(dict["a"]), noneToFalse(dict["b"]))
Here's a gist of the Playground I used while writing this answer: https://gist.github.com/bgrace/b8928792760159ca58a1

Simplify!
var dict = Dictionary<String,String>()
dict["a"] = "the letter a"
switch (dict["a"],dict["b"]) {
case (.None, let b):
println("false/nil, true \(b)")
case (let a, .None):
println("true, false/nil \(a)")
default:
println("don't know")
}

The accepted answer is out of date. So I rewrote it in Swift 5.
var dict = Dictionary<String,Bool>()
dict["a"] = true
dict["c"] = false
func matchOneOrTheOtherWithOptionals(_ a: Bool?, _ b: Bool?) -> String {
switch (a, b) {
case (.some(true), .none), (.some(true), .some(false)):
return "a was true, but b was None or false"
case (.none, .some(true)), (.some(false), .some(true)):
return "a was None or false and b was true"
default:
return "They both had a value, or they were both missing a value"
}
}
let xs: [Bool?] = [true, false, .none]
for a in xs {
for b in xs {
print("a = \(String(describing: a)), b=\(String(describing: b))")
print(matchOneOrTheOtherWithOptionals(a,b))
}
}

Related

How to use if let statement with conditions?

I know it's possible to express AND logic between if let statement and a condition like this
if let (Some(a), true) = (b, c == d) {
// do something
}
But what if I need an OR logic?
if let (Some(a)) = b /* || c == d */ {
// do something
} else {
// do something else
}
The only way I figure it out is as follows, but I think it's a little bit ugly as I have to write some code twice
if let (Some(a)) = b {
// do something
} else if c == d {
// do something
} else {
// do something else
}
If you have the same "do something" code in both cases then it must not use a. In that case you can use is_some:
if b.is_some() || c == d {
// do something
} else {
// do something else
}
In the more general case, you can use matches! to check if b matches a pattern without creating any bindings:
if matches!(b, Some(_)) || c == d {
// do something
} else {
// do something else
}

how I could create a metaclass that work with string ; numbers and null values

a metaclass that works with number value string value and null value
like this code ; please help me
String.metaClass.formatx = { delegate.toString().replaceAll(/null/, '0.0').toFloat() }
m= "4".formatx()
m2=4.formatx()
m3=null.formatx()
If I were you, I'd do the following:
String.metaClass.formatx = { -> delegate.toFloat() }
String a = "3"
String b = null
assert 3.0f == (a?.formatx() ?: 0.0f)
assert 0.0f == (b?.formatx() ?: 0.0f)
That is, defend against null in your code with ?. and ?:
If you have to try and catch the null, and format it, you could do:
import org.codehaus.groovy.runtime.NullObject
String.metaClass.formatx = { -> delegate.toFloat() }
NullObject.metaClass.formatx = { -> 0.0f }
String a = "3"
String b = null
assert 3.0f == a.formatx()
assert 0.0f == b.formatx()
But adding a method to NullObject feels wrong, and I've never done it before
Edit
This is shorter
import org.codehaus.groovy.runtime.NullObject
[String, Integer].each { it.metaClass.formatx = { -> delegate.toFloat() } }
NullObject.metaClass.formatx = { -> 0.0f }
println null.formatx()
println 3.formatx()
println "4".formatx()
I put this for example but I think THat I use much code
I repeat metaClass.formatx three times ; I dont know if is possible use OR setences INSTEAD
import org.codehaus.groovy.runtime.NullObject
String.metaClass.formatx = { -> delegate.toString().replaceAll(/null/, '0.0').toFloat() }
NullObject.metaClass.formatx = { -> delegate.toString().replaceAll(/null/, '0.0').toFloat() }
Integer.metaClass.formatx = { -> delegate.toString().replaceAll(/null/, '0.0').toFloat() }
m2= 4.formatx()
m= "4".formatx()
println null.formatx()
edit
import org.codehaus.groovy.runtime.NullObject
[String, Integer,NullObject].each { it.metaClass.formatx = { -> delegate.toString().replaceAll(/null/, '0.0').toFloat() } }
m2= 4.formatx()
m= "4".formatx()
println null.formatx()

Nested `each` loops in Groovy

Need guidance on the syntax of nested looping in groovy. How to use iterator to print values of (value of a.name, value of b.name) here?
List a
a.each {
print(it.name)
List b = something
b.each {
print(value of a.name, value of b.name)
}
}
List a
a.each { x ->
println(x.name)
List b = something
b.each { y ->
println(x.name + y.name)
}
}

swift How to use enum as parameter in constructing struct?

I was doing an experiment of Swift programming book and stuck with construct a struct inner the struct itself. But the error reported the parameter is unwrapped. How could I take it value as parameter?
struct Card {
var rank: Rank
var suit: Suit
func simpleDescription() -> String {
return "The \(rank.simpleDescription()) of \(suit.simpleDescription())"
}
func FullDeck() -> Card[] {
var deck: Card[]
for i in 1...13
{
for j in 0...3
{
let rank_para = Rank.fromRaw(i)
let suit_para = Suit.fromRaw(j)
**deck.append(Card(rank: rank_para, suit : suit_para ))
//value of optional type unwrapped;did you mean to use ? or !**
}
}
return deck
}
}
enum Rank: Int {
case Ace = 1
case Two, Three, Four, Five, Six, Seven, Eight, Nine, Ten
case Jack, Queen, King
func simpleDescription() -> String {
switch self {
case .Ace:
return "ace"
case .Jack:
return "jack"
case .Queen:
return "queen"
case .King:
return "king"
default:
return String(self.toRaw())
}
}
func compare(sec:Rank) -> Bool {
var first = 0
var second = 0
if self.toRaw() == 1 {
first = 1
} else {
first = self.toRaw()
}
if sec.toRaw() == 1 {
second = 1
} else {
second = self.toRaw()
}
return first > second
}
}
enum Suit: Int{
case Spades = 0
case Hearts, Diamonds, Clubs
func simpleDescription() -> String {
switch self {
case .Spades:
return "spades"
case .Hearts:
return "hearts"
case .Diamonds:
return "diamonds"
case .Clubs:
return "clubs"
}
}
}
the fromRaw method returns an optional value: Rank? and Suit?. That means that the value could be nil. You need to check for that:
if let aRank = rank_para {
if let aSuit = suit_para {
deck.append(Card(rank: aRank, suit: aSuit))
}
}
By using "if let", you "unwrap" the optional value into a value (aRank and aSuit) that is no longer optional (cannot be nil).
Another way to do that:
if rank_para and suit_para {
deck.append(Card(rank: rank_para!, suit: suit_para!))
}
Here, you are checking if rank_para and suit_para are nil. If they both are not, you call append and "unwrap" the optional values using !. ! means if the value is nil throw a runtime error, otherwise, treat this variable as if it cannot be nil.

Groovy numeric String compare

What do I do wrong:
assert 'foo' == 'foo' //PASS
assert '500' == '500' //PASS
assert '500' < '1000' //FAIL <-- Supposed to pass
assert '500' <= '1000' //FAIL <-- Supposed to pass
assert '1000' > '500' //FAIL <-- Supposed to pass
assert '1000' >= '500' //FAIL <-- Supposed to pass
It is for a customizable "condition" object:
class Condition {
static def compareClosure = [
'==' : { a, b -> a == b},
'!=' : { a, b -> a != b},
'<' : { a, b -> a < b},
'<=' : { a, b -> a <= b},
'>' : { a, b -> a > b},
'>=' : { a, b -> a >= b}
]
String comparator
def value
Condition(String comparator, String value) {
this.value = value
this.comparator = comparator
}
boolean isSatisfiedBy(def value) {
compareClosure[comparator](value, this.value)
}
}
So
assert new Condition('<=', '1000').isSatisfiedBy('500') //FAIL
Is there a way to do this without converting value to a numeric type ?
The short answer to your question is no.
However, I have a feeling this is for sorting purposes. If that is the case. Here is the sort function I use for this purpose.
Example in action: Groovy Web Console
Closure customSort = { String a, String b ->
def c = a.isBigDecimal() ? new BigDecimal(a) : a
def d = b.isBigDecimal() ? new BigDecimal(b) : b
if (c.class == d.class) {
return c <=> d
} else if (c instanceof BigDecimal) {
return -1
} else {
return 1
}
}
['foo','500','1000', '999', 'abc'].sort(customSort)

Resources