Storing and accessing object array in dictionary - Swift 3 - macOS - swift

So I'm not 100% sure if this is even the right way about this but I have a class that stores a few variables, I then have an array that stores theses objects.
I've been trying to put these objects into a dictionary for easy understanding so that I don't have to have several arrays, the idea being I could use the dictionary key to identify which set of arrays I want.
For example I have
class Player {
init(FirstName: String, LastName:String, Team: String, Pos: String, Line: Int, GaP: Int, Sh: Int, ShotPerc: Float, TOIPerG: Float, ShiPerG: Float, TOIPerShi: Float, FaceOffPer: Float, HitA: Int, HitF: Int, SavePerc: Float){
lastName = LastName
firstName = FirstName
team = Team
pos = Pos
line = Line
GP = GaP
sh = Sh
shotPerc = ShotPerc
TOIPerGame = TOIPerG
shiftsPerGame = ShiPerG
TOIPerShift = TOIPerShi
faceOffPerc = FaceOffPer
hitA = HitA
hitF = HitF
savePerc = SavePerc
}
I then store these in separate arrays filtered by the team (only showing relevant code but I parse a CSV file into array of Player and then use filter to put them into appropriate array)
players.append(Player(FirstName: record["First Name"]!, LastName: record["Last Name"]!, Team: record["Team"]!, Pos: record["Pos"]!, Line: Int(record["Line"]!)!, GaP: Int(record["GP"]!)!, Sh: Int(record["Sh"]!)!, ShotPerc: Float(record["ShotPerc"]!)!, TOIPerG: Float(record["TOIPerGame"]!)!, ShiPerG: Float(record["ShiftsPerG"]!)!, TOIPerShi: Float(record["TOIPerShift"]!)!, FaceOffPer: Float(record["FOffPerc"]!)!, HitA: Int(record["HitA"]!)!, HitF: Int(record["HitF"]!)!, SavePerc: Float(record["SavePerc"]!)!))
var FLA = [Player]()
var TBL = [Player]()
var DET = [Player]()
var WSH = [Player]()
var PIT = [Player]()
var NYR = [Player]()
var NYI = [Player]()
This seem messy ergo wanting to put them all into a dictionary but I can only get one object into it, presumably because it's wiping the key. My question is how do I get it to store all of the players under the same key?
var dict: [String: Array<Player>] = [:]
for (player, _) in LAK.enumerated(){
dict = ["LAK":[LAK[player]]]
}
print(dict["LAK"]?[0].fullName())
I'm presuming it's more along the lines of
dict["LAK"] =
but I feel like I'm going in circles!
Thanks!

You cannot store multiple values under the same key. That defeats the whole purpose of Key-Value storage. One key should map to one value.
You can store the array of your players instead, but that kind of defeats the purpose of using a dictionary.
Dictionaries should be used when you have unique keys (identifiers) for objects that you want them accessible under. In your case, you could use the player names for that, provided that they are all unique.

If you want to store to store all players under same key then first collect all players and then add it to the corresponding key.
let suppose you read player from csv. I am writing pseudo code.
// For playerData in readPlayerFormCSV()
// Now you will create a Player Object using data
// player = Player(playerData)
// One you have the player object
// create the dictionary where you want to store them
var dict: [String: Array<Player>] = [:]
// Check which team the player belongs
// if player belongs to LAK then add it player array with team key.
dict["LAK"].append(player)
My question is how do I get it to store all of the players under the same key?
If you just want players under a single key, Just add it to the corresponding array. I would not recommend this because the purpose of Dictionary is to store "Key-Value" pairs and adding just a single key doesn't make sense. It better to use an array.
dict["Your Key"].append(player)

Related

Should I use NSUserDefault or CoreData for saving the last ten scores?

Right now I have a struct with multiple dictionaries and string that holds the user's score for each level and the user's name that they type. I then save the struct scores into an NSUserdefault.
struct Scores: Codable {
var userName: String = ""
var totalScore: Int = 0
var highScore: [String : Int] = [:]
var scoreA: [String : Int] = [:]
var scoreB: [String : Int] = [:]
}
UserDefaults.standard.set(try? PropertyListEncoder().encode(scores), forKey:"scores_1")
This works well but I will need to save the user's last ten scores. I am wondering if I should use core-data or keep using NSUserdefaults? Not sure which is best practice.
Edit: Should I save the data in a .json file?
UserDefaults is best used to store small amounts of data, and not arrays.
Every time you call the key, the entire plist file that it's stored in is called into memory.
eg)
let volumeLevel = UserDefaults.Standard.integer(forKey: "volume")
So if you are storing an array that grows every time the user plays, eventually you will have memory problems.
With the example you have above, using UserDefaults to store High Score and UserName is fine, but I would recommend using CoreData (or something else) to store an array that has data for each run of the game.

Dictionary data structure returns nil in Swift

I am trying to implement a dictionary data structure in swift that stores an Array of Strings. I have declared it like:
var journeyDetails = [Int: [String]]()
When I want to append an actual string to it, I do
if let journeys = fetchedData["journeys"] as? [[String: Any]]{
var nr_of_journey : Int = 0
for journey in journeys{
self.journeyDetails[nr_of_journey]?.append("The starting date and time of the journey are: "+String(describing: journey["startDateTime"]))
}
}
nr_of_journey = nr_of_journey + 1
etc etc. However, journeyDetails keeps returning nil. Should I do any other type of initialization? Why is the data not appended?
Initially there are no keys or values in journeyDetails so every use of self.journeyDetails[nr_of_journey] returns nil.
If you are using Swift 4, you can specify a default value to be used if there currently isn't a value for the given key.
Update the line:
self.journeyDetails[nr_of_journey]?.append("The starting date and time of the journey are: "+String(describing: journey["startDateTime"]))
to:
self.journeyDetails[nr_of_journey, default: []].append("The starting date and time of the journey are: "+String(describing: journey["startDateTime"]))
This provides a default empty array if there currently isn't a value for the given nr_of_journey key.

how to add multiple key value pairs to dictionary Swift

okay, i'm trying to have the user add a key and value pair to a dictionary i created and have it show up in a table view. i do that just fine but i cant seem to figure out how to add another pair. when i go to add another it replaces the last one. id really like to have multiple pairs. can someone help please?
heres my code:
//declaring the dictionary
var cart = [String:String]()
//attempting to add to dictionary
cart[pizzaNameLabel.text!] = formatter.stringFromNumber(total)
This is how dictionary works:
In computer science, an associative array, map, symbol table, or
dictionary is an abstract data type composed of a collection of (key,
value) pairs, such that each possible key appears at most once in the
collection.
So
var cart = [String:String]()
cart["key"] = "one"
cart["key"] = "two"
print(cart)
will print only "key" - "two" part. It seems that you may need an array of tuples instead:
var cart = [(String, String)]()
cart.append(("key", "one"))
cart.append(("key", "two"))
print(cart)
will print both pairs.
From Swift 5.0, you can use KeyValuePairs like ordered dictionary type with multiple keys.
See this Apple Document of KeyValuePairs. ;)
let recordTimes: KeyValuePairs = ["Florence Griffith-Joyner": 10.49,
"Evelyn Ashford": 10.76,
"Evelyn Ashford": 10.79,
"Marlies Gohr": 10.81]
print(recordTimes.first!)

Create a dictionary in a loop in Swift

I have a variable set of objects that I need to place in a dictionary. I'm trying to add them to the dictionary in a for loop but from what I'm understanding dictionaries are immutable so they need to be declared immediately. How do I create a dictionary list of items that are not predetermined?
var newItems = [:]
for item in self.items{
newItems["\(item.key)"]["name"] = "A new item"
}
does not use the second value
var newItems : [String:String] = [:]
for i in 1..10{
newItems[i.description] = "A new item"
}
for more information https://www.weheartswift.com/dictionaries/
The problem with your original code is that dictionaries only have one key, so this construct newItems["\(item.key)"]["name"] is syntactically incorrect. If you had a fixed number of properties you could use a struct and put that in a dictionary. As you posed the question, though, you need to create a dictionary where the stored elements themselves are dictionaries. So, although I didn't actually put this into Xcode, it's a template for what you need to do:
var newItems = [:[:]]()
for item in self.items {
var itemDict = [:]()
for prop in whereeveryourpropertiescomefrom {
itemDict[prop] = valueforthisproperty
}
newItems["\(item.key)"] = itemDict
}
Of course, if your properties were initially stored in a dictionary unique to this item (equivalent of the inner loop), just store it directly into newItems.
Then, you could reference things as
let value = newItems["\(item.key)"]?.["property key"]
Notice the dictionary retrieval returns an optional you have to deal with.
The solution was when initializing the dictionary to create another dictionary
var newItems: [String:[String:AnyObject]]()

Save array of classes into Firebase database using Swift

I have an array of classes, which looks like this:
var myItems = [myClass]()
class myClass: NSObject {
var a: String?
var b: String?
var c: String?
var d: String?
}
What I want is to save the array called myItems into my database, and have every class inside of a personal section inside the database. Basically, I want every class to look like the one called "Eko" in this image:
To clarify, after "Eko" all the rest of the classes which is inside of the array myItems should be displayed. To achieve what the picture is demonstrating, I used this code:
let data = self.myItems[0]
let currU = FIRAuth.auth()?.currentUser?.uid
let userRef = self.ref.child("users").child(currU!).child(data.a!)
userRef.updateChildValues(["a": data.a!, "b": data.b!, "c": data.c!, "d": data.d!])
Obviously, this will only save the class at index 0 from the array myItems into the Firebase Database, which is displayed in the image above.
My question is thus, how do I save the entire array into the database? With my code I can only save 1 class from the array, and I would like to save all of the items into the database, so that they end up looking the same way that the one class does in the image. You could compare this to populating a tableView, where you need the "indexPath.row" to populate it with all the items instead of only one. I hope that I was clear enough!
You can't save a class into Firebase. But.. A class has a similar structure to a dictionary (properties and values, like key: value pairs etc).
Arrays in Firebase should generally be avoided - they have limited functionality and the individual elements cannot be accessed and for any changes you have to re-write the entire array.
Using a structure where the parent key names are created with childByAutoId is usually preferred.
The easiest solution is to simply add intelligence to the class so it would craft a dictionary and then save itself.
Craft a user class
UserClass
var name = String()
var food = String()
func saveToFirebase() {
let usersRef = myFirebase.child(users)
let dict = ["name": self.myName, "food", self.myFood]
let thisUserRef = usersRef.childByAutoId()
thisUserRef.setValue(dict)
}
}
and and array to store them
var usersArray = [Users]()
populate the array
var aUser = UserClass()
aUser.name = "Leroy"
aUser.food = "Pizza"
usersArray.append(aUser)
var bUser = UserClass()
bUser.name = "Billy"
bUser.food = "Tacos"
usersArray.append(bUser)
and then iterate over the array saving each user
for user in usersArray {
user.saveToFirebase()
}
this will result in
users
-Ykasokokkpoad
name: Leroy
food: Pizza
-YJlaok9sk0sd
name: Billy
food: Tacos
which is very similar to the structure you want. There are many other ways of creating this structure. For example, you could craft the entire dictionary in code and write it all out at one time.
Pardon typo's, I wrote this on the fly.
Firebase has no native support for arrays. If you store an array, it really gets stored as an "object" with integers as the key names.
// we send this
['hello', 'world']
// Firebase stores this
{0: 'hello', 1: 'world'}
Read this post for better understanding.