How to write mutating function for enum in Swift - swift

I want to write mutating function like the following. But this code cannot be compiled because x and y are immutable and copied value. I want to get the reference of x and y. How to get the reference of variables wrapped by enum?
enum Fruit {
case apple(Int)
case banana(Int, Int, Int)
mutating func increment() {
switch self {
case let .apple(x):
x += 1
case let .banana(x, y, z):
x += 1
}
}
}
var a = Fruit.banana(100, 200, 300)
a.increment()
I know the following code can do the same thing. But I think this solution is redundant because we have to write each variable twice.
enum Fruit {
case apple(Int)
case banana(Int, Int, Int)
mutating func increment() {
switch self {
case let .apple(x):
self = .apple(x + 1)
case let .banana(x, y, z):
self = .banana(x + 1, y, z)
}
}
}
var a = Fruit.banana(100, 200, 300)
a.increment()

Using self = .apple(x) will do the trick. It is customary, but you already knew this.
enum Fruit {
case apple(Int)
case banana(Int, Int, Int)
mutating func increment() {
switch self {
case let .apple(x):
self = .apple(x + 1)
case let .banana(x, y, z):
self = .banana(x + 1, y + 1, z + 1)
}
}
}
var a = Fruit.banana(100, 200, 300)
a.increment()
You could also add support for generic operators:
enum Fruit {
case apple(Int)
case banana(Int, Int, Int)
mutating func operate(_ op: (Int, Int) -> Int,_ num: Int) {
switch self {
case let .apple(x):
self = .apple(op(x, num))
case let .banana(x, y, z):
self = .banana(op(x, num), op(y, num), op(z, num))
}
}
}
var a = Fruit.banana(100, 200, 300)
a.operate(+, 1) // adds all by 1
a.operate(*, 500) // multiplies all by 500
You could also add support for an array of generic operators:
enum Fruit {
case apple(Int)
case banana(Int, Int, Int)
mutating func operate(_ nest: [((Int, Int) -> Int, Int)]) {
for i in nest {
switch self {
case let .apple(x):
self = .apple(i.0(x, i.1))
case let .banana(x, y, z):
self = .banana(i.0(x, i.1), i.0(y, i.1), i.0(z, i.1))
}
}
}
}
var a = Fruit.banana(100, 200, 300)
a.operate([(+, 500), (*, 2)]) // Adds all by 500, then multiply all by 2
Here's a nice simplification
If it were up to me, this is what I would do to get rid of repeating self =. You can simplify this further if you wish.
enum FruitList: String { case apple, banana }
struct Fruit {
static func apple(_ one: Int) -> Fruit {
return Fruit.init(.apple, [one])
}
static func banana(_ one: Int,_ two: Int,_ three: Int) -> Fruit {
return Fruit.init(.apple, [one, two, three])
}
var picked: (FruitList, [Int])
init(_ fruit: FruitList,_ list: [Int]) {
picked = (fruit, list)
}
mutating func operate(_ nest: [((Int, Int) -> Int, Int)]) {
for i in nest {
for j in 0..<picked.1.count {
picked.1[j] = i.0(picked.1[j], i.1)
}
}
}
}
var a = Fruit.apple(100)
a.operate([(+, 500), (*, 2)]) // Add all by 500, then multiply all by 2

Related

Why does it occur error: type of expression is ambiguous without more context?

I am studying the swift programming language.
Now I'm looking at how opaque types works.
Why does it occur error: type of expression is ambiguous without more context? (Swift 5.1)
protocol NumericExpression {
associatedtype TNumeric: Numeric
var value: TNumeric { get }
}
struct Expression {
static func sum<TA: NumericExpression, TB: NumericExpression>(_ a: TA,_ b: TB) -> some NumericExpression
where TA.TNumeric == TB.TNumeric {
return NumericExpressionSum(a: a, b: b)
}
static func multi<TA: NumericExpression, TB: NumericExpression>(_ a: TA, _ b: TB) -> some NumericExpression
where TA.TNumeric == TB.TNumeric {
return NumericExpressionMulti(a: a, b: b)
}
}
extension Int: NumericExpression {
var value: Self {
return self
}
}
struct NumericExpressionSum<TA: NumericExpression, TB: NumericExpression>: NumericExpression
where TA.TNumeric == TB.TNumeric {
let a: TA
let b: TB
var value: TA.TNumeric { a.value + b.value }
}
struct NumericExpressionMulti<TA: NumericExpression, TB: NumericExpression>: NumericExpression
where TA.TNumeric == TB.TNumeric {
let a: TA
let b: TB
var value: TA.TNumeric { a.value * b.value }
}
No compile error.
Sample code with compile error:
var s1 = Expression.sum(1, 2)
var s2 = Expression.sum(2, 3)
var m1 = Expression.multi(s1, s2)
var m2 = Expression.multi(3, 4)
print(m1.value) // 15
print(m2.value) // 12
print(type(of: m1)) // NumericExpressionMulti<NumericExpressionSum<Int, Int>, NumericExpressionSum<Int, Int>>
print(type(of: m2)) // NumericExpressionMulti<Int, Int>
print(type(of: m1).TNumeric) // Int
print(type(of: m2).TNumeric) // Int
let m3 = Expression.multi(m1, m2) //Error: type of expression is ambiguous without more context
Does this work for swift 5.5?
Thanks!

Extended capability for a more restrictive generic

I have a generic binary search tree based on Comparable:
public class BSTree<T: Comparable> {
public func insert(_ val: T, _ n: Int) {
// ...
}
#discardableResult
public func delete(_ val: T, _ n: Int) -> Int {
// ...
}
}
I want to add the ability to provide the sum of the values, if T is an arithmetic type. I tried the following:
public class BSTree<T: Comparable> {
private var sumStorage: T?
public func insert(_ val: T, _ n: Int) {
if let arithVal = val as? AdditiveArithmetic {
for _ in 0 ..< n { sumStorage += arithVal }
}
// ...
}
#discardableResult
public func delete(_ val: T, _ n: Int) -> Int {
// ...
numDeleted = ...
if let arithVal = val as? AdditiveArithmetic {
for _ in 0 ..< numDeleted { sumStorage -= arithVal }
}
}
}
extension BSTree where T: AdditiveArithmetic {
public var sum: T {
sumStorage as? T ?? T.zero
}
}
Of course, when I try to cast val as AdditiveArithmetic I get “Protocol 'AdditiveArithmetic' can only be used as a generic constraint because it has Self or associated type requirements”. Plus sumStorage isn’t AdditiveArithmetic, so I can’t add to it, and I can’t make it a stored property of the extension, because ... you just can’t.
What I finally came up with was to use inheritance:
class SummedBSTree<T>: BSTree<T> where T: AdditiveArithmetic & Comparable {
public var sum = T.zero
override public func insert(_ val: T, _ n: Int) {
super.insert(val, n)
for _ in 0 ..< n { sum += val }
}
#discardableResult
override public func delete(_ val: T, _ n: Int) -> Int {
let numDeleted = super.delete(val, n)
for _ in 0 ..< numDeleted { sum -= val }
return numDeleted
}
}
This works, but it seems like it’s a case of using a sledgehammer where a jeweler’s screwdriver should be able to do the trick. It’s frustrating that something that would be so easy to do in Objective-C (and other less strongly typed languages) is so difficult in Swift. Can someone come up with a way of adding the summing capability without subclassing?
import UIKit
//https://stackoverflow.com/questions/61784548/swift-extended-capability-for-a-more-restrictive-generic
protocol ON1Speedable {
associatedtype Item: Comparable
var sumStorage: Item? { get set }
}
public class BSTree<T: Comparable> {
var sumStorage: T?
init(sumStorage: T? = nil) {
self.sumStorage = sumStorage
}
}
extension ON1Speedable where Item: AdditiveArithmetic, Item: Strideable, Item.Stride: SignedInteger {
mutating func insert(_ val: Item, _ n: Int) {
sumStorage = sumStorage ?? Item.zero
for _ in 0..<n { sumStorage! += val }
}
#discardableResult
mutating func delete(_ val: Item, _ n: Int) -> Item? {
sumStorage = sumStorage ?? Item.zero
for _ in Item.zero..<val { sumStorage! -= val }
return sumStorage
}
}
extension BSTree: ON1Speedable { }
var g2 = BSTree<Int>(sumStorage: 0)
g2.sumStorage
g2.insert(5, 5)
g2.sumStorage // 25
g2.delete(5, 5) // 0
var g3 = BSTree<String>()
g3.sumStorage // nil
//g3.insert("foo", 5) // Error: Referencing instance method 'insert' on 'ON1Speedable' requires that 'String.Stride' conform to 'SignedInteger'
g3.sumStorage // nil
//g3.delete("bar", 5) // Error: Referencing instance method 'delete' on 'ON1Speedable' requires that 'String.Stride' conform to 'SignedInteger'

Apply void function on array

I am learning swift right now and wanted to write a quicksort algorithm for [Int]
func swap(array:[Int], x:Int, y:Int)->[Int] { //swap elements in array
var result:[Int] = array
result[y] = array[x]
result[x] = array[y]
return result
}
func split(array:[Int], u:Int, o:Int , p:Int)->Int { //where the sorting happens
let pivot:Int = array[p]
swap(array: array, x: p, y: o)
var pn:Int = u
for j in u...o {
if(array[j] <= pivot) {
swap(array: array, x: pn, y: j)
pn = pn+1
}
}
swap(array: array, x: pn, y: o);
return pn;
}
func quickSortR(array:[Int],u:Int ,o:Int) { //recursive call
if(u < o){
let p:Int = o
let pn:Int = split(array: array, u: u, o: o, p: p)
quickSortR(array: array,u: u,o: pn-1)
quickSortR(array: array,u: pn+1,o: o)
}
}
func quickSort(array:[Int]) { //initial call
quickSortR(array: array, u: 0, o: array.count-1)
}
My problem is that I don't know how to apply this implementation on an array.
For example if I got the array a:[Int] = [3,1,2].
I can't check if the implementation is working by print(quickSort(a)), because the return type of quickSort is void.
Of course I can't apply quickSort on that array like a.quickSort(a)
I really don't want to change my implementation of the algorithm by much if it isn't the cause of that problem (e.g. just the signature or return type)
Just improve your syntax:
func swap(array: inout [Int], x:Int, y:Int) { //swap elements in array
let temp = array[x]
array[x] = array[y]
array[y] = temp
}
func split(array: inout [Int], u:Int, o:Int , p:Int) -> Int { //where the sorting happens
print(ar, u , o , p)
let pivot:Int = array[p]
swap(array: &array, x: p, y: o)
var pn:Int = u
for j in u..<o {
if(array[j] <= pivot) {
swap(array: &array, x: pn, y: j)
pn = pn+1
}
}
swap(array: &array, x: pn, y: o);
return pn;
}
func quickSortR(array: inout [Int],u:Int ,o:Int) { //recursive call
if(u < o){
let p:Int = o
let pn:Int = split(array: &array, u: u, o: o, p: p)
quickSortR(array: &array,u: u,o: pn-1)
quickSortR(array: &array,u: pn+1,o: o)
}
}
func quickSort(array: inout [Int]) { //initial call
quickSortR(array: &array, u: 0, o: array.count-1)
}
If you use func swap(array: [Int]) array is immutable inside the method. It just copies. Using inout resolves this problem.
To check the code use somethink like this:
var ar = [1]
quickSort(array: &ar)
print(ar)

swift calculator operation in a switch case

i am new in programming swift.i have made this code by following other tutorials but i can´t find the correct write typ to perform operation?
#IBAction func operation(_ sender: UIButton) {
let operate = sender.currentTitle!
switch operate {
case "+" : performOperation() {}
case "-" : performOperation() {}
case "*" : performOperation() {}
case "/" : performOperation() {}
default: break
}
}
func performOperation(operate: (Double, Double) -> Double) {
}
performOperation method accepts an argument of type (Double, Double) -> Double.
Now this argument can be any of the below:
Method-1. A closure of type (Double, Double) -> Double
Method-2. A method name having signature as (Double, Double) -> Double
The below example uses both the methods:
func operation()
{
let operate = sender.currentTitle!
switch operate
{
case "+" : performOperation(operate: add) //using Method-2
case "-" : performOperation(){(a: Double, b: Double) -> Double in
return a - b
}//using Method-1
default: break
}
}
func add(a: Double, b: Double) -> Double
{
return a + b
}
func performOperation(operate: (Double, Double) -> Double)
{
let x = operate(3, 4)
print(x)
}
Similarly, you can use any of the 2 methods for all other cases of switch statement.

How to find the index of an item in a multidimensional array swiftily?

Let's say I have this array:
let a = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
Now I want something like this:
public func indicesOf(x: Int, array: [[Int]]) -> (Int, Int) {
...
}
so that I can call it like this:
indicesOf(7, array: a) // returns (2, 0)
Of course, I can use:
for i in 0..<array.count {
for j in 0..<array[i].count {
if array[i][j] == x {
return (i, j)
}
}
}
But that is not even close to swifty!
I want a way to do this which is swifty. I think maybe I can use reduce or map?
You can simplify your code slightly with enumerate() and indexOf().
Also the function should return an optional tuple because the element
might not be present in the "matrix". Finally, you can make it generic:
func indicesOf<T: Equatable>(x: T, array: [[T]]) -> (Int, Int)? {
for (i, row) in array.enumerate() {
if let j = row.indexOf(x) {
return (i, j)
}
}
return nil
}
You can also make it an extension for a nested Array of Equatable
elements:
extension Array where Element : CollectionType,
Element.Generator.Element : Equatable, Element.Index == Int {
func indicesOf(x: Element.Generator.Element) -> (Int, Int)? {
for (i, row) in self.enumerate() {
if let j = row.indexOf(x) {
return (i, j)
}
}
return nil
}
}
if let (i, j) = a.indicesOf(7) {
print(i, j)
}
Swift 3:
extension Array where Element : Collection,
Element.Iterator.Element : Equatable, Element.Index == Int {
func indices(of x: Element.Iterator.Element) -> (Int, Int)? {
for (i, row) in self.enumerated() {
if let j = row.index(of: x) {
return (i, j)
}
}
return nil
}
}
Swift 5+
extension Array where Element : Collection,
Element.Iterator.Element : Equatable, Element.Index == Int {
func indicesOf(x: Element.Iterator.Element) -> (Int, Int)? {
for (i, row) in self.enumerated() {
if let j = row.firstIndex(of: x) {
return (i, j)
}
}
return nil
}
}
Version accepting a closure, similar to index(where:), so there it is usable on the array of any elements, not only Equatable
extension Array where Element : Collection, Element.Index == Int {
func indices(where predicate: (Element.Iterator.Element) -> Bool) -> (Int, Int)? {
for (i, row) in self.enumerated() {
if let j = row.index(where: predicate) {
return (i, j)
}
}
return nil
}
}
Use like this:
let testArray = [[1,2,3], [4,5,6], [7,8]]
let testNumber = 6
print(testArray.indices(of: testNumber))
print(testArray.indices{$0 == testNumber})
Optional((1, 2))
Optional((1, 2))
Also, it can be used with IndexPath:
extension Array where Element : Collection, Element.Index == Int {
func indexPath(where predicate: (Element.Iterator.Element) -> Bool) -> IndexPath? {
for (i, row) in self.enumerated() {
if let j = row.index(where: predicate) {
return IndexPath(indexes: [i, j])
}
}
return nil
}
}