Swift: adding optionals Ints - swift

I declare the following:
var x:Int?
var y:Int?
and I'd like a third variable z that contains the sum of x and y. Presumably, as x & y are optionals, z must also be an optional:
var z:Int? = x + y
but this gives a complier error "value of optional type 'Int?' not unwrapped; did you mean to use '!' or '?'"
If I unwrap x & y:
var z:Int? = x! + y!
I get a run-time error as x & y are nil, so can't be unwrapped.
I can achieve the desired result as follows:
var z:Int?
if let x1 = x {
if let y1 = y {
z = x1+y1
}
}
but this seems a bit verbose for adding together 2 integers! Is there a better way of achieving this?

Here is my take, I think it's cleaner:
let none:Int? = nil
let some:Int? = 2
func + (left: Int?, right:Int?) -> Int? {
return left != nil ? right != nil ? left! + right! : left : right
}
println(none + none)
println(none + some)
println(some + none)
println(some + some)
println(2 + 2)
With results of:
nil
Optional(2)
Optional(2)
Optional(4)
4

The best I can think of is:
if x && y {
z = x! + y!;
}
Since they are all Optionals... there's really no way to avoid:
checking that they aren't nil
Unwrapping them before you add them.

Best solution IMO:
z = x.map { x in y.map { $0 + x } }
Did you know the map operator on Optional<T>? It is very nice.
Documentation says:
If self == nil, returns nil. Otherwise, returns f(self!).

It depends exactly what you're trying to achieve, but you could do it with an optional tuple:
var xy: (Int, Int)?
var z: Int
if let (x1, y1) = xy {
z = x1 + y1 // Not executed
}
xy = (3, 4)
if let (x1, y1) = xy {
z = x1 + y1 // 7
}
Update
As #Jack Wu points out, this changes the semantics. If you were willing to be a bit more verbose, you could however do it as follows:
func optIntAdd(x: Int?, y: Int?) -> Int? {
if let x1 = x {
if let y1 = y {
return x1 + y1
}
}
return nil
}
operator infix +! { }
#infix func +! (x: Int?, y: Int?) -> Int?{
return optIntAdd(x, y)
}
var x: Int?
var y: Int?
var z: Int?
z = x +! y // nil
x = 1
z = x +! y // nil
y = 2
z = x +! y // 3
Not sure "+!" is a useful choice of name for the operator, but it would't let me choose "+?".

Someday, we'll have variadic generics. Until then, you need a pair of overloads for all arities.
var z = Optional(x, y).map(+)
public extension Optional {
/// Exchange two optionals for a single optional tuple.
/// - Returns: `nil` if either tuple element is `nil`.
init<Wrapped0, Wrapped1>(_ optional0: Wrapped0?, _ optional1: Wrapped1?)
where Wrapped == (Wrapped0, Wrapped1) {
self = .init((optional0, optional1))
}
/// Exchange two optionals for a single optional tuple.
/// - Returns: `nil` if either tuple element is `nil`.
init<Wrapped0, Wrapped1>(_ optionals: (Wrapped0?, Wrapped1?))
where Wrapped == (Wrapped0, Wrapped1) {
switch optionals {
case let (wrapped0?, wrapped1?):
self = (wrapped0, wrapped1)
default:
self = nil
}
}
}

z = (x ?? 0) + (y ?? 0)
* Worked on Xcode 9 *

Swift 5.5 Sum any optional values
infix operator +?: AdditionPrecedence
public func +? <T: AdditiveArithmetic>(lhs: T?, rhs: T?) -> T {
if let lhs = lhs, let rhs = rhs {
return lhs + rhs
} else if let lhs = lhs {
return lhs
} else if let rhs = rhs {
return rhs
} else {
return .zero
}
}

Related

Swift - declare 2d array contains

I want to say that if some 2d array contains the "point" format [Int,Int], then regenerate the random numbers, not counting the iteration.
for _ in 0..<33{
let j = Int(arc4random_uniform(10))
let k = Int(arc4random_uniform(10))
while live.contains(//The point j,k){
live.append(Array(arrayLiteral: j,k))
cells[j][k] = true
}
}
From what I understood your question, you want to generate an array of 2D points excluding repetition, you can use CGPoint or define your own Point
struct Point: Equatable {
let x: Int
let y: Int
}
func == (lhs: Point, rhs: Point) -> Bool {
return lhs.x == rhs.x && lhs.y == rhs.y
}
var live: [Point] = []
for _ in 0..<10{
var candidate = Point(x: Int(arc4random_uniform(10)), y: Int(arc4random_uniform(10)))
while live.contains(candidate) {
candidate = Point(x: Int(arc4random_uniform(10)), y: Int(arc4random_uniform(10)))
}
live.append(candidate)
}
or you can use tuple like so
var live: [(Int, Int)] = []
for _ in 0..<10{
var j = Int(arc4random_uniform(10))
var k = Int(arc4random_uniform(10))
while live.contains({$0 == (j, k)}) {
j = Int(arc4random_uniform(10))
k = Int(arc4random_uniform(10))
}
live.append((j,k))
}
Depending on your problem size, it might be more optimal to build an array of all possible values, and then shuffle and take first X elements every time you need new set of random points. You can optimize it further, but the code'd look similar to:
var possibleValues: [Point] = []
for x in 0..<5 {
for y in 0..<5 {
possibleValues.append(Point(x: x, y: y))
}
}
func randomPoints(numberOfPoints: Int) -> [Point] {
// shuffle original array without changing it
let shuffled = possibleValues.sorted { _ in arc4random_uniform(10) > 5 }
// take first X elements
return Array(shuffled[0..<numberOfPoints])
}
randomPoints(numberOfPoints: 10)
You can optimize this solution even further but that'd require to know more about your data set. Hope this helps

Why something like optional chaining is not applied to all expressions and function calls in swift?

If there is an ability of optional chaining in swift like a?.b, which returns optional of type of b, why there is no ability to unwrap optionals like this:
let x: Int? = 5, y: Int? = 6
let z: Int?
z = x? + y?
I mean: apply + (or any other function) if all the arguments have values, or return 'nil' otherwise. It looks very useful for me, so I am not sure, if I am not missing something understanding this.
The why is not really answerable, it would be rather opinion based - although there's a good rationale from the Swift team for not implementing implicit stuff in the Swift realm.
But you can easily define a new + operator for your optional Ints:
func +(lhs: Int?, rhs: Int?) -> Int? {
if let l = lhs, r = rhs {
return l + r
}
return nil
}
let x: Int? = 5, y: Int? = 6
let z = x + y
You can also use flatmap to remove optionality and reduce to sum like this,
let z = [x, y].flatMap { $0 }.reduce(0, combine: +)

Shorthand for assignment if nil in Swift?

if x == nil {
x = y
}
I know the statement above can be rewritten as:
x = x ?? y
But x ??= y is not accepted by compiler. Is there a shorthand not to repeat x?
Check this out, put the following in global code space(In your Extensions.swift maybe). This creates a custom operator you can use throughout your entire project.
Swift 2
infix operator ??= {}
func ??= <T>(inout left: T?, right: T) {
left = left ?? right
}
Swift 3
infix operator ??=
func ??= <T>(left: inout T?, right: T) {
left = left ?? right
}
Usage:
var foo: String? = nil
var bar = "Bar"
foo ??= bar
print("Foo: \(bar)")
Hope this helps :)
Laffen’s answer is great. However, it is not exactly equivalent to x = x ?? y as the right hand side is always evaluated with their definition of ??= as opposed to the standard ?? operator.
If you want to have this behavior too, #autoclosure is here to help:
infix operator ??=
func ??=<T>(left: inout T?, right: #autoclosure () -> T) {
left = left ?? right()
}
This code works in playground:
var x: Int? = nil
let y = 5
x = x ?? y // x becomes 5
and
var x: Int? = 6
let y = 5
x = x ?? y // x stays 6
By the way here are some variants of checking for nil:
if x != nil {
// classic
}
if x != .None {
// nil in Swift is enum with value .None
}
if let _x = x {
// if you need it's value
}
if let _ = x {
// if you don't need it's value
}
UPD: code for project - copy and run it:
var x: Int? = nil
let y = 5
x = x ?? y
print (x)
x = 7
x = x ?? y
print (x)

Shorthand for no re-assignment with the nil coalescing operator (??)

Is there a shorthand for doing this:
var x: Int = 42;
var y: Int? = nil
x = y ?? x
E.g. re-assigning same value/not re-assigning, if y is nil
Edit: To clarify, in the example, I'd like to keep the value (42) of x, if y is nil. A better wording might be an "assign if not nil" operator.
Edit2: As #rintaro pointed out, reassignment may incur side-effects which I would like to avoid. I could resort to if let like this:
var x: Int = 42;
var y: Int? = nil
if let y = y {
x = y
}
but that is pretty verbose.
There is no builtin operator for that.
Use map instead:
map(y) { x = $0 }
// OR
y.map { x = $0 }
Note: this technique is useful when the variable is observed:
var x: Int = 42 {
didSet {
println("didSet")
}
}
var y: Int? = nil
x = y ?? x // `didSet` is called
map(y) { x = $0 } // `didSet` is not called

How do you overload an operator in swift?

Say you have a class C. It has two instance variables, number and vector. vector is just an array of either ints or doubles.
I would like to do the following:
c1 = C()
c1.number = 2
c1.vector = [1,2,3]
c2 = C()
c2.number = 3
c2.vector = [4,6,7]
println(c1.number + c2.number) \\print to screen 5
println(c1.vector + c2.vector) \\ print [5,8,10]
Basically, I'm looking to overload the "+" operator so that it knows which "version" of the "+" to use depending of the type.
The + operator is already defined for the type Array. It does an array merge and tacks the values of the rvalue onto the lvalue. To do a sum of values by index you can do something like this:
protocol Numeric { }
extension Double: Numeric {}
extension Int: Numeric {}
func +<T: Numeric>(left: [T], right: [T]) -> [T]? {
var numElements: Int = 0
if count(left) != count(right) {
return nil
} else {
numElements = count(left)
}
var result = [T]()
for var i = 0; i < numElements; ++i {
if let lvalue = left[i] as? Int, rvalue = right[i] as? Int {
result.append(lvalue + rvalue as! T)
} else if let lvalue = left[i] as? Double, rvalue = right[i] as? Double {
result.append(lvalue + rvalue as! T)
}
}
return result
}
But generally, I wouldn't advise overriding a predefined operator because of the high potential to cause confusion and chaos later on down the road.