What Data Structure should I use for this particular case? - swift

I have a dictionary, something like this
var dict = [String : [String]]()
The functionality I want to achieve is that, I have a hashtable which I can quick get the list of data from.
In my code, I use a dictionary and an array.
I am not very good with algorithem and data structure, so I am wondering if there is any better data structure that is suitable for something like this?

Use:
var dict = [String : [String]]()
Swift already has built in search algorithms that allow you you to retrieve data inside of your dictionary with simple subscript syntax like so
dict["element"]

You will use it in this way -
Declaration:
var dict: [String: [String]] = [:]
Initialise:
dict["element"] = myArray

Related

How to add value to dictionary without replacing it?

I'm trying to append values inside dictionary without replacing it for example:
var dict = [String:Any]()
dict["login"] = ["user" : "jon"]
//...
//...
//...
dict["login"] = ["password": "1234"]
When I'm trying to add a value to login at the second time , it's overwrite the first value.
How can I append this data?
I'm using Swift 3.
Edit: let me rephrase my question a little bit.
I want to build a dynamic dictionary which I'll post it to alamoFire as body parameters. so if I have an JSON that looks like this:
{
"name" : "Jon",
"details" : {
"occupation" : "lifeguard"
"years_of_ex" : 3
}
"more_details" : "extra info"
"inner_body" : {
"someInfo" : "extra info"
}
... // there might be lots of other fields since it's dynamic
... // the server expect to have missing fields and not empty ones
}
I want to add dynamically details since I don't know how my Dictionary would looks like.
so adding to values to dictionary without override them is a must for me.
Define an intermediate variable and assign to it:
var dict = [String:Any]()
dict["login"] = ["user" : "jon"]
if var login = dict["login"] as? [String: String] {
login["password"] = "1234"
dict["login"] = login
}
To reflect for the edit in the question: without knowing the exact structure of the dictionary, you cannot modify it as you wish. Anyways, modifying a JSON dictionary directly is really bad practice.
Parse the JSON response into a custom object, modify the object as you wish, then encode the object back to JSON and use it as your request's body.
If you don't want to write the JSON parsing function yourself, have a look at ObjectMapper. It can both map a JSON response to objects and can also map an object to JSON.
you cannot directly "append" new values to a dinamic dictionary without knowing the type and content.
Since
dict["login"]
returns you a Any? you have no way to directly manipulate it.
Do you have any ideas of the possible combinations of the content of each dictionary leaf?
you could write a recursive methods that tries to downcast the content of the leaf and base on it, try to do something
switch dict["login"] {
case is [String: Any?]:
// check that the key does not already exist, to not replace it
case is [Int: Any?]:
// Do something else
}

How to access CFDictionary in Swift 3?

I need to read and write some data from CFDictionary instances (to read and update EXIF data in photos). For the life of me, I cannot figure out how to do this in Swift 3. The signature for the call I want is:
func CFDictionaryGetValue(CFDictionary!, UnsafeRawPointer!)
How the heck do I convert my key (a string) to an UnsafeRawPointer so I can pass it to this call?
If you don't have to deal with other Core Foundation functions expecting an CFDictionary, you can simplify it by converting to Swift native Dictionary:
if let dict = cfDict as? [String: AnyObject] {
print(dict["key"])
}
Be careful converting a CFDictionary to a Swift native dictionary. The bridging is actually quite expensive as I just found out in my own code (yay for profiling!), so if it's being called quite a lot (as it was for me) this can become a big issue.
Remember that CFDictionary is toll-free bridged with NSDictionary. So, the fastest thing you can do looks more like this:
let cfDictionary: CFDictionary = <code that returns CFDictionary>
if let someValue = (cfDictionary as NSDictionary)["some key"] as? TargetType {
// do stuff with someValue
}
What about something like:
var key = "myKey"
let value = withUnsafePointer(to: &key){ upKey in
return CFDictionaryGetValue(myCFDictionary, upKey)
}
You can write something like this:
let key = "some key" as NSString
if let rawResult = CFDictionaryGetValue(cfDictionary, Unmanaged.passUnretained(key).toOpaque()) {
let result = Unmanaged<AnyObject>.fromOpaque(rawResult).takeUnretainedValue()
print(result)
}
But I guess you would not like to write such thing at any time you retrieve some data from that CFDictionary. You better convert it to Swift Dictionary as suggested in Code Different's answer.

how to make a swift dictionary that holds two items that are array of other items

I'd like to create a dictionary that holds two arrays (one key is called "locations" and the other is "items") like this:
var tmpResults = Dictionary("locations",Array)
tmpResults["items"]=Array
or something like this (neither of which seem to work):
var tmpResults = ["locations",:<Location>,"items":<Item>]
var tmpResults = ["locations":Array(Location),"items":Array(Item)]
but I'm really not sure how to do this in Swift. How would I specify the types that the arrays could hold?
I think the easiest solution would be AnyObject.
var tmpResults: [String: AnyObject] = [:]
tmpResults["locations"] = [location1, location2, location3]
tmpResults["items"] = [item1, item2, item3]
// Assuming location1, location2, and location3 are all of the same "Location" type
// And item1, item2, and item3 are all of the same "Item" type
By using AnyObject, your dictionaries objects could be almost anything. In this example, you have a dictionary that holds and array of Locations at one key, and an array of Items at another key.
You do lose some of the nice type-checking Swift does though.
Edit
In fact, you could declare it like this, so that the compiler at least knows your dictionary holds arrays:
var tmpResults: [String: [AnyObject]] = [:]
In either case, you use the array you'd probably do something like this:
if let items = tmpResults["items"] as? [Item] {
// Do something with you items here
}
In order to hold array in dictionary, you can go with the following code:
var tempResults : Dictionary<String, Array<String>>
This can be reduced to:
var tempResults : [String: [String]]
Then you can add your Array items to it:
var array1 : [String] = [String]()
array1.append("location1")
array1.append("location2")
array1.append("location3")
var array2 : [String] = [String]()
array2.append("item1")
array2.append("item2")
array2.append("item3")
And finally, you can add it to your Dictionary
tempResults["location"] = array1
tempResults["items"] = array2
Hope this helps!

Why I can not use SetValue for Dictionary?

Hello Everyone I am new in swift and In my app I declare a dictionary like this :
var imageDict : Dictionary<String, String> = [:]
and I want to set values for that dictionary like this :
imageDict.setValue(NSStringFromCGPoint(frame), forKey: NSString.stringWithString("/(tagValue)"));
But I got error like this :
Dictonary <String, String> does not have a member named 'setValue'
This question is from my previous question and can enybody explain my why I can not set value for that dictionar and can enybody tell me any other way to do that?
Thanks In advance.
Swift dictionary does not have method like setValue:forKey:. Only NSMutableDictionary has such methods. If you wish to assign value for key in swift, you should use subscripting. Here is the correct way to do it, if you wish to do it with swift dictionary.
var imageDict:[String: String] = [:]
imageDict["\(tagValue)"] = NSStringFromCGRect(frame)
Or if you wish to use NSMutableDictionary then, it looks like this,
var imageDict = NSMutableDictionary()
imageDict.setObject(NSStringFromCGRect(frame), forKey: "\(tagValue)")
I guess you need to use NSMutableDictionary.

SWIFT : Update Value NSDictionary

NSDictionary in this example :
var example: [Int:AnyObject] = [1:["A":"val","B":[1:["B1":"val"]]]]
how to update "B1" value OR should i not use NSDictionary for this complex value?
Thank you
I would suggest either of the following two options, but not a mix:
Find a way to structure you data, so you can use the power of the Swift Dictionary class.
Use a NSDictionary and ignore Swift's awesomeness.
Almost needless to say: It's so much better to go for the first option, if your data allows it. Using AnyObjects in a Dictionary isn't a good way. Note that you could also use structs to structure your data.
You cannot update this structure at all, because it implicitly has an immutable type. As a test:
var example: [Int: AnyObject] = [1:["A":"val","B":[1:["B1":"val"]]]]
if let dict=example[1] as? NSMutableDictionary {
"Mutable dictionary"
} else if let dict=example[1] as? NSDictionary {
"Immutable dictionary" // < THIS will be printed as a result
} else {
"Other"
}
Your model is pretty confusing - I would recommend classes/types that wrap your data and give you a better idea of what you're dealing with at each level.
It is possible to create this structure in such a way that the layered dictionaries are mutable, but it's a pain, and neither easy to read nor deal with.