"Deep-copy" of Swift dictionary with map()? - swift

I have a GKGameModel that stores its internal state in an array a of Cards and a dictionary b that maps from Ints to arrays of Cards. GameplayKit mandates that I must copy this internal state in setGameModel:.
The following code is meant to just-copy the array and "deep-copy" the dictionary. FWIK this should be sufficient since Cards themselves never change.
var a: [Card]
var b: [Int: [Card]]
func setGameModel(gameModel: GKGameModel) {
let otherGameModel = gameModel as! GameModel
a = otherGameModel.a
b = otherGameModel.b.map { (i: Int, cards: [Card]) in (i, cards) }
}
However, this causes the following syntax error in the line that attempt the "deep-copy":
Cannot assign a value of type '[(Int, [Card])]' to a value of type
'[Int, [Card]]'.
What am I doing wrong?

In your case:
b = otherGameModel.b
is sufficient.
Because, Array and Dictionary are both value types. So when it is assigned to another variable, it will be deep copied.
var bOrig: [Int: [Int]] = [1: [1,2,3], 2:[2,3,4]]
var bCopy = bOrig
bCopy[1]![2] = 30
bOrig[1]![2] // -> 3
bCopy[1]![2] // -> 30

The error message reveals there is a type mismatch:
variable b is declared as Dictionary<Int,[Card]> but the map function returns an Array of tuplets (Int, [Card])

Related

Trying to understand how constructors and different parameter types work inside classes in Swift

New to Swift but have some previous knowledge about C# and Java programming. Trying to understand how "Constructors" and parameter types work in Swift when creating and instantiating a class.
My problem is below:
public class MyClass {
private var somethingA : String
private var somethingB : String
private var somethingC : Int
private var complexes:[String:[String:Int]] = [String:[String:Int]]();
init() {
self.somethingA = "";
self.somethingB = "";
self.somethingC = 0;
self.complexes = [somethingA:[somethingB:somethingC]];
}
public func addSomething(somethingAA : String) {
self.somethingA = somethingAA;
}
public func addComplex(somethingAA: String, complex:(somethingBB: String, somethingCC: Int)) {
self.somethingA = somethingAA;
// How do I assign the complex:(somethingBB, somethingCC) parameter to my self variable 'complexes'?
}
}
When I tried doing it like the following, I get the following errors for each line:
self.somethingB = somethingBB; // Use of unresolved identifier 'somethingBB'
self.somethingC = somethingCC; // Use of unresolved identifier 'somethingCC'
self.complexes = [somethingAA:[somethingBB:somethingCC]]; //use of unresolved identifier 'somethingBB' and 'somethingCC'
the function addComplex(somethingAA: String, complex:(somethingBB: String, somethingCC: Int)) takes a tuple of name complex which consist of String and Int. To assign values from tuple to your properties, you need to use tupleName.propertyName kind of pattern, using this your addAddComplex function becomes
public func addComplex(somethingAA: String, complex:(somethingBB: String, somethingCC: Int)) {
somethingA = somethingAA
somethingB = complex.somethingBB
somethingC = complex.somethingCC
//create a dict with somethingB and somethingC values
complexes = [somethingAA: [somethingB: somethingC]]
print(complexes)
}
Now if you call function addComplex like below which will print ["AAA": ["BBB": 10]]
let myClass = MyClass()
myClass.addSomething(somethingAA: "Hellow")
myClass.addComplex(somethingAA: "AAA", complex: (somethingBB: "BBB", somethingCC: 10))
For error inside function addComplex, parameter complex is tuple, which contains two value named somethingBB of type String and somethingCC of typle Int.
So to access value from tuple you have to access it with dot notation.
self.somethingB = complex.somethingBB
self.somethingC = complex.somethingCC
or you can access parameters from tuple using below syntax also :
self.somethingB = complex.0
self.somethingC = complex.1
To assign value to complexes is type of Dictionary of key-value pair. Here key is type of String and value is another Dictionary of [String:Int]. So you have to construct same structure using raw values from function parameters inside function like below.
self.complexes = [somethingAA:[somethingBB:somethingCC]]
Try this code:
public func addComplex(somethingAA: String, complex:(somethingBB: String, somethingCC: Int)) {
self.somethingA = somethingAA;
self.somethingB = complex.somethingBB
self.somethingC = complex.somethingCC
self.complexes = [somethingAA:[somethingBB:somethingCC]]
}
Tuples are one of Swift's less visible language features. They occupy a small space between Structs and Arrays. In addition, there's no comparable construct in Objective-C (or many other languages).
A tuple can combine different types into one. Tuples are value types
and even though they look like sequences they aren't sequences, as
there's no direct way of looping over the contents.
There are different types of tuples:
// A simple tuple
let tuple1 = (2, 3)
let tuple2 = ("a", "b", "c")
// A named tuple
let tuple3 = (x: 5, y: 3)
// Different types of contents
let tuple4 = (name: "Carl", age: 78, friends: ["Bonny", "Houdon", "Miki"])
The ways in which you can access tuple elements are:
// Accessing tuple elements
let tuple5 = (13, 21)
tuple5.0 // 13
tuple5.1 // 21
let tuple6 = (x: 21, y: 33)
tuple6.x // 21
tuple6.y // 33
Now coming to your question the comlpex parameter is a named tuple In which
complex:(somethingBB: String, somethingCC: Int)
the first parameter in the tuple is somethingBB type of string and somethingCC type of Int.
You can simply access somethingBB and somethingCC by doing
self.somethingB = complex.somethingBB
self.somethingC = complex.somethingCC
or
self.somethingB = complex.0
self.somethingC = complex.1
It is unclear how you want to add the tuple to the complexes property. Do you want to add a new entry in the dictionary? Do you want to replace the existing dictionary with the parameter values?
You probably have a misunderstanding of how tuples work. This parameter:
complex:(somethingBB: String, somethingCC: Int)
Is a parameter called complex, with the type of (somethingBB: String, somethingCC: Int). There is not a single parameter called somethingBB or somethingCC. There is, however, complex.somethingBB and complex.somethingCC. Think of tuples in Swift like System.Tuple in C#, but better. That way, you wouldn't mistake somethingBB and somethingCC as parameters when they are just members of a tuple type.
Now, you should know how to add the tuple into the dictionary. If you want a new entry:
complexes[somethingAA] = [complex.somethingBB: complex.somethingCC]
If you want to replace the existing entry:
complexes = [somethingAA : [complex.somethingBB : complex.somethingCC]]
In production code, you should probably not use complex types like [String: [String: Int]], create a struct or class for it.
EDIT:
If you want to append an entry to the inner dictionary, you need to check whether there is a value associated with the key somethingAA first:
if complexes[somethingAA] == nil {
complexes[somethingAA] = [somethingBB: somethingCC]
} else {
complexes[somethingAA][somethingBB] = somethingCC
}

How to Represent Dictionary as NSValue in Swift 3?

I have the following Dictionary:
let example: [String: (Int, Int)] = ["test": (0, 1)]
I need to store this as an NSData variable, and to do that it must first be converted to an NSValue, which I try to do as follows:
let nsval = NSValue().getValue(example as! UnsafeMutableRawPointer)
Only to be met with the error:
Cannot convert value of type 'Void' (aka '()') to specified type 'NSValue'
I've seen SO answers that suggest using:
let test = UnsafeMutablePointer.load(example)
But that also yields the error:
Type 'UnsafeMutablePointer<_>' has no member 'load'
So then, how is one to convert a dictionary to an NSValue in Swift 3?
not all swift types are compatible with Foundation classes. So you cannot construct an NSValue containing the type [String: (Int, Int)] you can, however start out with an NSDictionary. Ditch the tuple and choose a type thats compatible with objc. then you can change type of let example: to NSDictionary. use that with the NSValue methods.
That said, if you're trying to turn general objc types into an NSData for general serialization purposes, you're going to get more milage out of the NSKeyedArchiver/NSKeyedUnarchiver methods like .archivedData(withRootObject: Any) -> Data (though they still don't support tuples.)
In theory, if you really want to turn a swift Tuple into a data object, you could do this.
var x:(Int, Int) = (4, 2)
var bytes:Data = withUnsafeBytes(of: &x){ g in
var d = Data()
for x in g {
d.append(x)
}
return d
}
heres the reverse:
var y:(Int, Int) = (0,0)
bytes.withUnsafeBytes { (x:UnsafePointer<(Int, Int)>) in
y = x.pointee
}
print(y) // prints (4, 2)
Beware: this is the path to the dark side.

Swift: Cast array of objects to array of sub type

Say I have an array of Animals and I'd like to cast it to an array of Cats. Here, Animal is a protocol that Cat adopts. I'd like something like let cats: [Cat] = animals as! [Cat] but this seg faults in compilation (btw I'm on both Linux Swift 3 and Mac Swift 2.2). My workaround is to just create a function that downcasts each item individually and adds it to a new array (see small example below). It produces the desired result, but isn't as clean as I'd like.
My questions are:
is this totally dumb and I'm just missing an easier way to do this?
how can I pass a type as the target parameter in the function below, rather than passing an instance? (e.g. I'd like to pass Cat.self rather than Cat(id:0) but doing so causes an error saying cannot convert Cat.Type to expected argument type Cat)
Here's what I have so far:
protocol Animal: CustomStringConvertible
{
var species: String {get set}
var id: Int {get set}
}
extension Animal
{
var description: String
{
return "\(self.species):\(self.id)"
}
}
class Cat: Animal
{
var species = "felis catus"
var id: Int
init(id: Int)
{
self.id = id
}
}
func convertArray<T, U>(_ array: [T], _ target: U) -> [U]
{
var newArray = [U]()
for element in array
{
guard let newElement = element as? U else
{
print("downcast failed!")
return []
}
newArray.append(newElement)
}
return newArray
}
let animals: [Animal] = [Cat(id:1),Cat(id:2),Cat(id:3)]
print(animals)
print(animals.dynamicType)
// ERROR: cannot convert value of type '[Animal]' to specified type '[Cat]'
// let cats: [Cat] = animals
// ERROR: seg fault
// let cats: [Cat] = animals as! [Cat]
let cats: [Cat] = convertArray(animals, Cat(id:0))
print(cats)
print(cats.dynamicType)
Am I missing an easier way to do this?
You can use map to make the conversion:
let cats: [Cat] = animals.map { $0 as! Cat }
how can I pass a type as the target parameter in the function below, rather than passing an instance?
First, you need to remove the instance parameter:
func convertArray<T, U>(array: [T]) -> [U] {
var newArray = [U]()
for element in array {
guard let newElement = element as? U else {
print("downcast failed!")
return []
}
newArray.append(newElement)
}
return newArray
}
Since you cannot specify type parameters explicitly, you need to provide the compiler with some info to deduce the type of U. In this case, all you need to do is to say that you are assigning the result to an array of Cat:
let cats: [Cat] = convertArray(animals)
As of Swift 4.1 using compactMap would be the preferred way, assuming you don't want the method to completely fail (and actually crash) when you have any other Animal (for example a Dog) in your array.
let animals: [Animal] = [Cat(id:1),Dog(id:2),Cat(id:3)]
let cats: [Cat] = animals.compactMap { $0 as? Cat }
Because compactMap will purge any nil values, you will end up with an array like so:
[Cat(1), Cat(3)]
As a bonus, you will also get some performance improvement as compared to using a for loop with append (since the memory space is not preallocated; with map it automatically is).

Mutating nested arrays in Swift Dictionary through custom accessor method

Say that we have a dictionary of arrays:
var dict: [Int: [Int]] = [:]
Is there something special about Dictionary's subscript methods? Can somebody explain why the following in-place append works:
dict[1] = []
dict[1]?.append(200)
// dict is now [1: [200]]
but the following doesn't:
var xs = dict[1]
xs?.append(300)
// dict is still [1: [200]], not [1: [200, 300]]
I (kind of) understand why the latter doesn't update the original dictionary, as it creates a copy of the array. But I don't understand why the first one works, I would assume that it similarly creates a copy.
More over (this is the actual problem I have), can I implement a method that allows similar in-place update behavior? The following code doesn't work:
extension Dictionary {
func mget(key: Key) -> Value? {
return self[key]
}
}
dict.mget(1)?.append(400)
It produces the following error:
49> d.mget(1)?.append(400)
repl.swift:49:12: error: immutable value of type '[Int]' only
has mutating members named 'append'
d.mget(1)?.append(400)
^ ~~~~~~

Swift Tuples - Different from struct and from each other?

How different are tuples in swift from structures? (1)
As I understand, both tuples and structures can be sent by value instead by reference in function calls, returns, right?
Also, I know that if have
var A : StructureX
var B : StructureX
I know that structure A and B have the same Type, which is StructureX. But...
let A : (Int, String)
let B : (Int, String)
Are A and B tuples the same Type? (2)
What are the advantages about using Tuples instead of structures? (3)
I find it's easiest to conceptualize Swift Tuples as "Anonymous Structs" with a few critical differences. They behave similarly, but a struct has a formal definition and allows more control over mutability, while tuples allow for pattern matching.
Similarities Between Tuples and Structs
Both may have any number of members of any type, including closures
Both can be constructed inline (see typealias in the code below)
Both prevent mutation of any members if declared as constants
If a tuple has labeled members, both structs and tuples allow member access by label
Differences Between Tuples and Structs
Structs require a definition before use
Structs do not allow pattern matching against their members
Structs allow mutability of members declared as variables if the instance is a variable
Tuples do not allow mutating functions or functions that refer to any of its members
Tuples may not implement Protocols
If a tuple has anonymous members, its members can be accessed by index, unlike structs
Some code for a playground illustrating these differences and similarities
// All commented code causes a compilation error. Uncomment to view error messages.
struct StructureX {
let a: Int = 0
var b: String = "string"
}
//
// Struct member variability
//
var structureA: StructureX = StructureX()
let structureB: StructureX = StructureX()
//structureA.a = 2 // declared as a constant, instance is variable
structureA.b = "allowed" // declared as a variable, instance is variable
//structureB.a = 2 // declared as constant, instance is constant
//structureB.b = "not allowed" // declared as constant, instance is constant
structureA = structureB // these are the same type
structureA
//
// A tuple can't be used as a literal to construct a struct.
//
//let StructureC: StructureX = (a: 17, b: "nope")
//
// Typealias a labeled tuple and it can be constructed similarly to a struct
//
typealias StructureT = (a: Int, b: String)
var structureD: StructureT = StructureT(a: 0, b: "asdf")
structureD
//structureD = structureA // but they are distinct types
let emptyTuple: () = () // philosophically, isn't this the definition of Void?
print(emptyTuple) // prints as ()
let single: (Int) = (23)
//let namedSingle: (a: Int) = (a: 42)
//
// Tuple Labeled Member Access
//
var labeledTupleA: (a: Int, b: String) = (a: 0, b: "string")
labeledTupleA.0 = 5
labeledTupleA.a
labeledTupleA
var check: (a: Int, b: String)
check = labeledTupleA // same type
check
//
// Tuples can have functions/closures
//
let labeledTupleB: (Int, String, fun: () -> Void) = (0, "string", { () -> Void in
print("hi")
})
labeledTupleB.1
labeledTupleB.fun()
//labeledTupleB.0 = 10 // this tuple is a constant, so all of its members are constant
//
// Tuples with members of the same type, but differet labels are not of the same type
//
var labeledTupleC: (c: Int, d: String) = (c: -1, d: "fail")
//labeledTupleC = labeledTupleA
//labeledTupleC = labeledTupleB
//
// Tuples with anonymous members matching the type pattern of a labeled member tuple are of equivalent type
//
var unlabeledTuple: (Int, String) = (0, "good")
unlabeledTuple = labeledTupleA
unlabeledTuple = labeledTupleC
//
// Tuples with closures may not refer to sibling members
//
var labeledTupleD: (de: Int, df: (Int) -> Void) = (de: 0, df: { (num: Int) -> Void in
//de += num
//self.de += num
print(num)
})
labeledTupleD.de
labeledTupleD.df(1)
//
// Tuples allow pattern matching, Structs do not
//
//switch structureA {
//case (let i, let s):
// print(i, s)
//default:
// break
//}
switch labeledTupleD {
case (_, let closure):
closure(123)
default:
break
}
I'm not sure the official terminology around tuples however, you declare them as if they were a special kind of type:
let A : (Int, String)
Maybe we could say that A is now a variable of type tuple? However, not all tuples are the same. If you declare variable of type tuple and try to assign it a tuple with parameters that differ in count, sequence, or type you'll get a compiler error. This will fail
let A : (Int, String) = ("Bob", 1234, 4.0)
Though this works fine:
let A : (Int, String) = (1234, "Bob")
Of course this strong type safety is also enforced with structs.
As far as the advantages, here are some thoughts on the differences I'm aware of.
Structures require that you define them before using them. Tuples, on the other hand, let you return an arbitrary list of values. How is this useful? I have an iPad app with a shopping cart view controller in it. There is a summary view in the cart view that displays a current status of what's in the cart at any given time--sometimes just normal items, but RMA items and items on re-order are also potentially in the cart. I have a method on my shopping cart class that returns a tuple containing cart count, RMA count, re-order count, and total count. I don't have to declare a structure to get back all four values. It's very convenient:
class Cart : NSManagedObject {
...
var totals : (cartCount:Int, rmaCount:Int, reorderedCount:Int, totalCount:Int) {
let cart = ... // Calculate cart count
let rma = ... // Calculate rma count
let reorder = ... // Calculate reorder count
let total = cart + rma + reorder // Add them all up
return (cart, rma, reorder, total)
}
}
In my cart view:
let cartValues = cart.totals
self.summaryView.cartCountLabel.text = "\(cartValues.cartCount)"
self.summaryView.rmaCountLabel.text = "\(cartValues.rmaCount)"
self.summaryView.reorderCountLabel.text = "\(cartValues.reorderedCount)"
self.summaryView.totalCountLabel.text = "\(cartValues.totalCount)"
There may be other reasons, but convenience is the most compelling one for me to prefer tuples in this scenario.