Swift - Dictionary with array of tuples - ios

I am trying to create a list to hold the data for a tableview with sections.
I would like to use it like that:
cell.NameLabel.text = list[indexPath.section][indexPath.row].name
Edited
I tried to make the question simple because english is not my main language.
let me try to ask the right question:
I would like to create a dictionary with array of tuples
Something like that:
var myDict = Dictionary<Array<(code: String, type: String)>>()
And I would like to access like that:
myDict["blue"][0].type

The declaration of myDict in your example is wrong, because a Dictionary requires the type of the keys and the type of the values. You should declare it as:
var myDic = Dictionary<String, Array<(code: String, type: String)>>()
Then, you can use it (almost) as you wanted to:
myDic["one"] = [(code: "a", type: "b")]
myDic["two"] = [(code: "c", type: "d"), (code: "e", type: "f")]
let t = myDic["two"]![0].type
...
Note the ! after the myDic["two"]. Thats because accessing a Dictionary by key returns an Optional, you need to unwrap it first.
Actually, this code would be better:
if let item: Array<(code: String, type: String)> = myDic["two"] {
let t = item[0].type
...
}

Well, this would be a very simple Array of Array of an object. I invite you to read the Apple Language Reference of Swift about collections and Arrays :
https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/CollectionTypes.html
import UIKit
class Object {
var name: String
init(string: String) {
name = string
}
}
var objects: [[Object]] = [[Object]]()
for section in 0..<3 {
for i in 0..<10 {
objects[section][i] = Object(string: "My Object \(section) \(i)")
}
}
let myString = objects[2][1].name

Related

How to iterate two arrays both containing custom classes simultaneously

lets say you have the classes:
class Artwork {
var title = ""
var location =""
var author = ""
}
class GroupedArtworks {
var location = ""
var artworks = [Artworks]()
}
then you have an variable that contains several objects of the class "Artwork":
var arts = [artwork1, artwork2...]
How would I group the objects of the class "Artwork" by "location"?
I would like to end up with another variable containing objects of the class "GroupedArtworks"
and for each object, in the attribute "artworks" have all the objects that have the same "location"
so something like:
var orderedArtworks = [groupedartworks1, groupedartworks2...]
No doubt for loops are involved here.
The solution is super easy with Swift's Dictionary init(grouping:by:)
let artworks: [Artwork] = []
// dictionary type will be [String: [Artwork]]
let dictionary = Dictionary(grouping: artworks, by: \.location)
// now we can easy iterate over (key: String, value: [Artwork]) pairs
let groups: [GroupedArtworks] = dictionary.map { location, artworks in
GroupedArtworks(location: location, artworks: artworks)
}
// or simply
let groups = dictionary.map(GroupedArtworks.init)
// Swift will infer the types of dictionary and the init
but you will need to add this init to your GroupedArtworks
class GroupedArtworks {
let location: String
let artworks: [Artwork]
init(location: String, artworks: [Artwork]) {
self.location = location
self.artworks = artworks
}
}
Documentation
As someone correctly pointed out in the comments, since dicts are unordered collections, your array of GroupedArtworks will be unordered one as-well. But this should not be a problem since you can easily sort it by lets say location.
let groups = dictionary.map(GroupedArtworks.init).sorted(by: \.location)

How to add optional values to an array in Swift

I'm having issues with appending an optional value to an array in Swift. The view I'm writing is for the creation of a routine for the gym. However my Routine object is not being instantiated as it should be.
I have experience with other programming languages but I am fairly new to Swift, and optionals.
My ViewController contains an optional variable:
var routine: Routine?
Where the Routine class contains:
name: String
exerciseList: [String]()
numOfSets: [Int]()
When I am preparing it to send the newly created routine to my other ViewController, I take the values from user input to edit the fields of the object.
let name = routineName.text ?? ""
let numberOne = Int(numOfSetsOne.text ?? "0") //numOfSetsOne is a text label
routine?.exerciseList.append(selectedExerciseOne!) //Haven't tested to see if this works yet
routine?.numOfSets[0] = numberOne! //This line is not working
routine = Routine(name: name)
To try a little debugging I put print statements on either side of the line like so:
print ("numberOne Value: \(numberOne!)")
routine?.numOfSets[0] = numberOne!
print ("numOfSets[0] Value: \(routine?.numOfSets[0])")
I expected the output from the second print statement to be identical to the first. However the terminal output:
numberOne Value: 3
numOfSets[0] Value: nil
Does anyone know what has gone wrong here?
Thanks
You have declared a property that may contain a Routine, but you have not assigned an instance of Routine to that property before trying to use it.
This means that, for example,
routine?.numSets[0] = numberOne!
doesn't do anything - routine is nil and so the statement is skipped.
You should create an appropriate init function for your Routine class and use that to create a new Routine and assign it to routine
For example:
class Routine {
var name: String
var exerciseList = [String]()
var numberOfSets = [Int]()
init(named: String) {
self.name = named
}
}
Then you can say
let name = routineName.text ?? ""
let numberOne = Int(numOfSetsOne.text ?? "0")
self.routine = Routine(named: name)
self.routine?.numberOfSets.append(numberOne!)
Coordinating related arrays can get a bit messy, so I would use a single array:
struct ExerciseSet {
let exerciseName: String
let sets: Int
}
class Routine {
var name: String
var exerciseList = [ExerciseSet]()
init(named: String) {
self.name = named
}
}
Your Routine is not initialised before its being assigned value
try
let name = routineName.text ?? ""
let numberOne = Int(numOfSetsOne.text ?? "0")
routine = Routine(name: name)
routine?.exerciseList.append(selectedExerciseOne!)
routine?.numOfSets[0] = numberOne!

How to map a json that I don't know the number of the parameters

Hello I have a json the returns me some parameters as variables.
It has Parameter1, Parameter2, Parameter3 etc..
I don't know how many parameters will it give me. It's not a list it's just different variables in the json.
Which is the best way to map a json like that? I use Object Mapper
For Example:
First Time the json is
{
"MyObject": {
"Parameter1": "p1",
"Parameter2": "p2",
"Parameter3": "p3",
"Parameter4": "p4"
}
}
And a second time the json is
{
"MyObject": {
"Parameter1": "p1",
"Parameter2": "p2",
"Parameter3": "p3"
}
}
You can try this.
let keyvalue = parentDict.value(forKey: "MyObject") as! NSDictionary
var lastValue = Keyvalue.allValues
var lastKey = Keyvalue.allKeys
for Keyname in Keyvalue.allKeys
{
print("Keyname %#",Keyname)
print("Value %#",Keyvalue.value(forKey:Keyname))
}
the first step to parse any JSON to make it reusable is to create your Model class or struct accordingly.
Create a class called MyObject as same as your json dictionary
Create a let/var property parameters: [String]?. It's optional as API isn't reliable and maybe wont send anything at all.
See the example below how I parse the json object below.
class MyObject {
let parameters: [String]?
// it's failable because maybe json different at runtime & couldn't parse
init?(json: [String:AnyObject]) {
var key = "Parameter"
var parms = [String]()
for i in 0..<json.count {
guard let item = json["\(key)\(i+1)"] as? String else { continue }
params.append(item)
}
self.parameters = params
}
}
Now you can access the parameters array with index.
Well this could be refactored and you can get the idea how you will handle this with that library.

What's the best way to store 2 x n Strings in Swift?

I would like to store a different count of String data pairs in this format:
string a[n][2]{
{"1","2"},
{"3","4"},
{"5","6"}
{... }};
I would like to add a new pair by using the append methode or something similar... But is that possible and nice to handle with a 2D array or should I use a dictionaire?? And how could I implement that? Thanks!
You could potentially use an array of tuples to solve this:
typealias StringPair = (String, String)
var myStrings = [StringPair]()
myStrings.append(StringPair("1", "2"))
Edit: To search for a string pair, you could do:
var doesItContain1 = myStrings.contains {
$0.0 == "1"
}
You could also change your type alias to use names:
typealias StringPair = (string1: String, string2: String)
And then filter with:
var doesItContain1 = myStrings.contains {
$0.string1 == "1"
}
Edit 2: To sort:
var sorted = myStrings.sort {
return $0.string1 < $1.string1
}

How to use Swift specific containers in containers?

I have a Dictionary that holds another Dictionary that holds an Array which holds another Array of a custom class. I'm having a lot of trouble working with these can someone who this comes easy to tell me the ways I can define, initialize, and access and assign to either part specifically.
Dic = [String: [String: [[MyClass]]]]
Sorry if it's confusing.
This code shows you how to do what you asked, but the data structure you requested is quiet cumbersome to use. I'll recommend to think again about what you want to accomplish and review this data structure.
class MyClass {
var name : String
init(name: String) {
self.name = name
}
}
// Create your dictionary
var dic : [String: [String: [[MyClass]]]] = [:]
// Create a list of MyClass object
var list = [MyClass(name: "first"), MyClass(name: "second"), MyClass(name: "third")]
// Create a dictionary with string key and array of array of type MyList
var myClassDic = ["test": [list]]
// update or add new value via the updateValue method
dic.updateValue(myClassDic, forKey: "index1")
// update or add new value via the subscript
dic["index2"] = ["test2": [[MyClass(name: "forth"), MyClass(name: "fith")]]]
// Iterate over your outer dictionairy
for key in dic.keys {
// retrieve an entry from your outer dictionary
var tempDic = dic[key]
// Iterate over your inner dictionary
for sKey in tempDic!.keys {
// retrieve an array of array of MyList Object
var containerList = tempDic![sKey]
// iterate over the outer array
for listVal in containerList! {
//Iterate over the inner array
for sListVal in listVal {
print("\(sListVal.name) ")
}
println()
}
}
}

Resources