As far as I know the recommended way to use optionals (Int in this example) is the following:
var one:Int?
if var maybe = one {
println(maybe)
}
Is it possible to use a shorter way to do something like the following?
var one:Int?
var two:Int?
var three:Int?
var result1 = one + two + three // error because not using !
var result2 = one! + two! + three! // error because they all are nil
Update
To be more clear about what I'm trying to do: I have the following optionals
var one:Int?
var two:Int?
var three:Int?
I don't know if either one or two or three are nil or not. If they are nil, I wan't them to be ignored in the addition. If they have a value, I wan't them to be added.
If I have to use the recommended way I know, it would look something like this: (unnested)
var result = 0
if var maybe = one {
result += maybe
}
if var maybe = two {
result += maybe
}
if var maybe = three {
result += maybe
}
Is there a shorter way to do this?
Quick note - if let is preferred for optional binding - let should always be used where possible.
Perhaps Optionals aren't a good choice for this situation. Why not make them standard Ints with a default value of 0? Then any manipulation becomes trivial and you can worry about handling None values at the point of assignment, rather than when you're working on the values?
However, if you really want to do this then a tidier option is to put the Optionals into an Array and use reduce on it:
let sum = [one,two,three,four,five].reduce(0) {
if ($1) {
return $0 + $1!
}
return $0
}
That's exactly the point of optionals — they may be nil or non-nil, but unwrapping them when they're nil is an error. There are two types of optionals:
T? or Optional<T>
var maybeOne: Int?
// ...
// Check if you're not sure
if let one = maybeOne {
// maybeOne was not nil, now it's unwrapped
println(5 + one)
}
// Explicitly unwrap if you know it's not nil
println(5 + one!)
T! or ImplicitlyUnwrappedOptional<T>
var hopefullyOne: Int!
// ...
// Check if you're not sure
if hopefullyOne {
// hopefullyOne was not nil
println(5 + hopefullyOne)
}
// Just use it if you know it's not nil (implicitly unwrapped)
println(5 + hopefullyOne)
If you need to check multiple optionals at once here there are a few things you might try:
if maybeOne && maybeTwo {
println(maybeOne! + maybeTwo!)
}
if hopefullyOne && hopefullyTwo {
println(hopefullyOne + hopefullyTwo)
}
let opts = [maybeOne, maybeTwo]
var total = 0
for opt in opts {
if opt { total += opt! }
}
(It seems you can't use the let optional binding syntax with more than one optional at once, at least for now...)
Or for extra fun, something more generic and Swifty:
// Remove the nils from a sequence of Optionals
func sift<T, S: Sequence where S.GeneratorType.Element == Optional<T>>(xs: S) -> GeneratorOf<T> {
var gen = xs.generate()
return GeneratorOf<T> {
var next: T??
do {
next = gen.next()
if !next { return nil } // Stop at the end of the original sequence
} while !(next!) // Skip to the next non-nil value
return next!
}
}
let opts: [Int?] = [1, 3, nil, 4, 7]
reduce(sift(opts), 0) { $0 + $1 } // 1+3+4+7 = 15
Related
According to Swift documentation:
Optional binding can be used with if and while statements to check for a value inside an optional, and to extract that value into a constant or variable, as part of a single action.
The documentation only shows an example of optional-binding using if statement like:
if let constantName = someOptional {
statements
}
I'm looking for an example of optional-binding using while loop?
It's the same
while let someValue = someOptional
{
doSomethingThatmightAffectSomeOptional(with: someValue)
}
Here is a concrete example of iterating a linked list.
class ListNode
{
var value: String
var next: ListNode?
init(_ value: String, _ tail: ListNode?)
{
self.value = value
self.next = tail
}
}
let list = ListNode("foo", ListNode("bar", nil))
var currentNode: ListNode? = list
while let thisNode = currentNode
{
print(thisNode.value)
currentNode = thisNode.next
}
// prints foo and then bar and then stops
I think the advantage of using while let ... is infinite loop that check some variable for any changes. But it's weird. For this kind of work you should use didSet. Or other good example is List data structure. Anyway, here is the example:
var value: Int? = 2
while let value = value {
print(value) // 2
break
}
I wish to use guard-let to assign a variable to an expression, but I want to modify the expression before assigning. If the expression is nil, then the else block should be entered, otherwise the variable should be assigned to f(expression). Here is an example of what I would like to do:
let arr: [Int] = []
// Do stuff, maybe add elements to arr
guard let x = abs(arr.first) else { return } // Syntax error
// If arr was nonempty, then we want x = abs(arr.first!)
But Swift does not allow this syntax because abs requires a non-optional argument, and arr.first is optional. So is there any way to evaluate arr.first, and then if it is not nil to assign abs(arr.first!) to x? I know that I could do this with if-let or by using two variables (one from the guard-let and then one that gets assigned to the absolute value of that variable). But guard-let seems like the tool for the job, if only there were some way to accomplish this.
let arr:[Int] = [-1,1,3,-9]
guard let x = arr.first.flatMap({ $0 < 0 ? -$0: $0 }) else { return }
// ...
or (UPDATE based on dfri's notes)
// ....
let arr:[Int] = [-1,1,3,-9]
guard let x = arr.first.map(abs) else { return }
Optional(Some<Int>) -> Int -> Optional<abs(Some<Int)> -> Int ... meh
You could do a dirty guard let ..., let ... else fix as follows (forcing the binded certainly-not-nil value of x to become an optional which you subsequently immediately unwrap and bind to xAbs)
func foo() {
let arr: [Int] = [-1, 2, -3, 4]
guard let x = arr.first,
let xAbs = Optional(abs(xAbs)) else { return }
print(xAbs, xAbs.dynamicType)
}
foo() // 1 Int
This doesn't look very pretty however, and I would, personally, prefer adding an Int extension and make use of optional chaining, as I will cover next.
Instead: use extensions and optional chaining
Unless you explicitly need to store x as well as xAbs, an alternative and more Swifty approach is to use optional chaining in combination with a simple extension to Int:
extension Int {
var absValue: Int { return abs(self) }
}
func foo() {
let arr: [Int] = [-1, 2, -3, 4]
guard let xAbs = arr.first?.absValue else { return }
print(xAbs, xAbs.dynamicType)
}
foo() // 1 Int
Since arr.first is an optional Int variable, you can implement whatever method/computed property you wish onto self as an extension to Int, and access that method/property using optional chaining arr.first?.someMethod()/arr.first?.someProperty (as .absValue above).
Or, simply modify your arr.first (unwrapped) value after the guard let ... else block
I see no reason, however (other than the technical discussion) not to introduce an additional immutable holding the absolute value of x. This will also increase code readability, at least w.r.t. to the dirty guard let ..., let ... else fix above.
// ...
guard let x = arr.first else { return }
let xAbs = abs(x)
Or, if you find it acceptable for your xAbs property to be mutable, out of a theoretical perspective your could remove the middle-man immutable by using a guard var ... block rather than guard let ...
guard var xAbs = arr.first else { return }
xAbs = abs(xAbs)
This should probably only be used, however, if xAbs is to be mutated again (i.e., use immutables whenever you really don't need mutables, and never the other way around).
I think the cleanest and simplest solution would be like this:
guard let first = arr.first else { return }
let x = abs(first)
Now the calculation abs(first) is only reached if arr.first != nil.
What you want can be achieved using case let.
let arr: [Int] = [1,2,3,4]
guard let first = arr.first, case let absolute = abs(first) else { return }
// use `absolute`
I have a quick question that is confusing me a little bit. I made a simple average function that takes an array of optional Ints. I check to make sure the array does not contain a nil value but when I use reduce I have to force unwrap one of the two elements in the closure. Why is it that I only force unwrap the second one (in my case $1!)
func average2(array: [Int?]) -> Double? {
let N = Double(array.count)
guard N > 0 && !array.contains({$0 == nil}) else {
return nil
}
let sum = Double(array.reduce(0) {$0+$1!})
let average = sum / N
return average
}
I know it is simple but I would like to understand it properly.
The first parameter of reduce is the sum, which is 0 in the beginning. The second one is the current element of your array which is an optional Int and therefore has to be unwrapped.
Your invocation of reduce does this:
var sum = 0 // Your starting value (an Int)
for elem in array {
sum = sum + elem! // This is the $0 + $1!
}
EDIT: I couldn't get a more functional approach than this to work:
func average(array: [Int?]) -> Double? {
guard !array.isEmpty else { return nil }
let nonNilArray = array.flatMap{ $0 }
guard nonNilArray.count == array.count else { return nil }
return Double(nonNilArray.reduce(0, combine: +)) / Double(nonNilArray.count)
}
You can also discard the second guard if you want something like average([1, 2, nil]) to return 1.5 instead of nil
I want to initialize a dictionary with a dictionary nested inside like this:
var a = [Int:[Int:Float]]()
a[1][2] = 12
But I get an error:
(Int:[Int:Float]) does not have a member named 'subscript'
I've hacked at a variety of other approaches, all of them running into some kind of issue.
Any idea why this doesn't work?
You can create your own 2D dictionary like this:
struct Dict2D<X:Hashable,Y:Hashable,V> {
var values = [X:[Y:V]]()
subscript (x:X, y:Y)->V? {
get { return values[x]?[y] }
set {
if values[x] == nil {
values[x] = [Y:V]()
}
values[x]![y] = newValue
}
}
}
var a = Dict2D<Int,Int,Float>()
a[1,2] = 12
println(a[1,2]) // Optional(12.0)
println(a[0,2]) // nil
The point is you access the element via a[x,y] instead of a[x][y] or a[x]?[y].
It's giving you that error because your first subscript returns an optional so it may return a dictionary or nil. In the case that it returns nil the second subscript would be invalid. You can force it to unwrap the optional value by using an exlamation point.
var a = [1 : [ 2: 3.14]]
a[1]
a[1]![2]
If you aren't positive that a[1] is non-nil you may want to safely unwrap with a question mark instead.
var a = [1 : [ 2: 3.14]]
a[1]
a[1]?[2]
You can also assign using this method. (As of Beta 5)
var a = [Int:[Int:Float]]()
a[1] = [Int: Float]()
a[1]?[2] = 12.0
a[1]?[2] //12.0
Another way to do it is with an extension to the standard dictionary:
extension Dictionary {
mutating func updateValueForKey(key: Key, updater: ((previousValue: Value?) -> Value)) {
let previousValue = self[key]
self[key] = updater(previousValue: previousValue)
}
}
Example:
var a = [Int:[Int:Float]]()
a.updateValueForKey(1) { nestedDict in
var nestedDict = nestedDict ?? [Int:Float]()
nestedDict[2] = 12
return nestedDict
}
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.