How can I convert a String to a Dictionary type in Swift? - swift

I have a String
example:
"['name': 'consumer_nam', 'date': 'date']"
I want to convert this to a dictionary type in Swift4.

Dictionaries in Swift can be represented by [String : Any], and many other ways.
let dictionary : [String : Any] = ["name" : "consumer_nam", "date" : "date"]
If what you're trying to do is parse the String, you can take a look here and here.

It looks like your String is supposed to be interpreted as a Dictionary. It looks a bit like a textual representation of JSON.
Find a spec for the exact format of that String, and then you write code to parse it.
It may be easier to convince whoever produced that string to produce for example a JSON document instead (which would be stored as Data, not String).

Related

How to use compact map on custom type?

I am about reduce code by using compact map. But I can't convert custom struct into [String: String] type.
struct Sample {
let key: String
let value: String
}
let all = [Sample]()
I want to make array all samples into dictionary. So I used compact map & It returns error
Cannot convert value of type '[[String : String]]' to specified type
'[String : String]'
But I don't know exactly what I need to use.
let dictionary: [String: String] = all.compactMap{[$0.key: $0.value]}
Please help me to find out correct solutions. Thank you all in advance...
You can use .reduce(into:_:):
let dictionary = all.reduce(into: [:]) { dict, elem in
dict[elem.key] = elem.value
}

What Data Structure should I use for this particular case?

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

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
}

Contextual type 'AnyObject' cannot be used with dictionary literal multi level dictionary

I'm running into an issue with creating a multi-level dictionary in Swift and have followed some of the suggestions presented here:
var userDict:[String:AnyObject]? = ["SystemId": "TestCompany",
"UserDetails" : ["firstName": userDetail.name, "userAddress" : "addressLine1" userDetail.userAdd1]]
The use of [String:AnyObject]? works for the first level of the Dict, but Swift is throwing the same error at the next level Dict, UserDetail[]. Any suggestions would be greatly appreciated
I'm not pretty sure what are the types of userDetail.name and userDetail.userAdd1 but if they are Strings you should let it [String:String]?
However, [String:Any]? should solve your problem. If you are sure that you want to let it [String:AnyObject]? (I don't think that you want to), you can do something like this:
var userDict:[String:AnyObject]? = ["SystemId": "TestCompany" as AnyObject,
"UserDetails" : ["firstName": userDetail.name, "userAddress" : userDetail.userAdd1] as AnyObject]
Hope this helped.

How do I put different types in a dictionary in the Swift Language?

Swift only allows a dictionary to contain a single type.
Here's the definition that is taken from the Swift book:
A dictionary is a container that stores multiple values of the same type
[...]
They differ from Objective-C’s NSDictionary and NSMutableDictionary classes, which can use any kind of object as their keys and values and do not provide any information about the nature of these objects.
If that’s the case then how are we going to create nested dictionaries?
Imagine we have a plist that holds String, Array and Dictionary items in it . If I’m allowed to hold only the same of type of items (either string, array etc.) then how am I going to use different types of items stored in the plist?
How do I put different types in the same dictionary in Swift?
You can achieve plist-like nested structures using Any type for dictionary values which is Swift's somewhat counterpart to Objective-C's id type but can also hold value types.
var response = Dictionary<String, Any>()
response["user"] = ["Login": "Power Ranger", "Password": "Mighty Morfin'"]
response["status"] = 200
EDIT:
Any seems to be better than AnyObject because in the above code response["status"] is of type Swift.Int, while using value type of AnyObject it is __NSCFNumber.
As has been suggested, you can use the Any type to represent a plist dictionary's values. But then how do you work with the data? Cast every value any time you look it up from the dictionary? That's really messy. A better, more type-safe way to model a plist would be to take advantage of Swift's enums, also known as algebraic data types or discriminated unions. They let you specify exactly what types are permitted in the dictionary and avoid ever having to cast. Here's an implementation, explained:
// An atomic (i.e. non-collection) data type in a plist.
enum PListNode {
case PLN_String(String)
case PLN_Integer(Int)
case PLN_Float(Double)
case PLN_Bool(Bool)
case PLN_Date(CFDate)
case PLN_Data(CFData)
}
At the most atomic level, only the above data types may be stored in a plist. Each 'node' in the plist can ultimately can only be one of these types. So we create an enum which lets us specify this.
// A value that can be stored in a plist Dictionary's key-value pair.
enum PListValue {
case PLV_Node(PListNode)
case PLV_Array(PListNode[])
case PLV_Dictionary(Dictionary<String, Box<PListValue>>)
}
typealias PList = Dictionary<String, Box<PListValue>>
A plist is basically a dictionary of key-value pairs, and each value can be either an atomic (i.e. non-collection) value; or it can be an array of atomic values; or it can be a dictionary of string-plist value pairs. The above enum expresses these constraints, and the typealias gives the plist type an easy-to-remember name.
Given the above types, we can completely express any given plist in a type-safe way, e.g.:
// Example translated from
// https://developer.apple.com/library/Mac/documentation/Darwin/Reference/ManPages/man5/plist.5.html
let myPlist: PList = [
"Year Of Birth": Box(PLV_Node(PLN_Integer(1965)))
, "Pets Names": Box(PLV_Array([]))
, "Picture": Box(PLV_Node(PLN_Data(...)))
, "City of Birth": Box(PLV_Node(PLN_String("Springfield")))
, "Name": Box(PLV_Node(PLN_String("John Doe")))
, "Kids Names": Box(
PLV_Array([PLN_String("John"), PLN_String("Kyra")])
)
]
What it means to be type-safe here is that you can process any given plist using a switch statement and cover all possibilities without the need for any casting. You're eliminating a whole class of potential runtime errors. E.g.:
// See https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Enumerations.html#//apple_ref/doc/uid/TP40014097-CH12-XID_189 for explanation
switch myPlist["Year Of Birth"] {
case Box(.PLV_Node(let plvNodeValue)):
...
case Box(.PLV_Array(let plvArrayValue)):
...
case Box(.PLV_Dictionary(let plvDictionaryValue)):
...
}
Note that it's necessary to wrap up recursive data structures in a 'box' (a pointer to the actual value) to keep their sizes finite.
NSObject works for my case while "Any" does not
var d:Dictionary<String,NSObject> = [:]
d["key1"] = "ddd"
d["key2"] = 111 //OK
NSLog("%#", d) //OK
var d2:Dictionary = Dictionary<String,Any>()
d2["key1"] = "ddd"
d2["key2"] = 111
NSLog("%#", d2) //I got error here
Use NSMutableDictionary like this :
var dictInfo : NSMutableDictionary = [ "lang_key": "1"]
dictInfo["food_type"] = lbl_TypeOfFood.text
dictInfo["search_text"] = txt_Search.text
dictInfo["date"] = lbl_Date.text
dictInfo["opening_hours"] = lbl_OpeningHours.text
hope this will work fine .
Use: Dictionary<String, AnyObject>
var dict: Dictionary<String, AnyObject> = [
"number": 1,
"string": "Hello",
]
NSMutableDictionary to Dictionary works like a charm and will allow you to put different types in a Dictionary in the Swift Language:
let nsMutableDictionary = NSMutableDictionary()
nsMutableDictionary[NSFontAttributeName] = UIFont(name: "HelveticaNeue", size: 12.0)!
nsMutableDictionary[NSForegroundColorAttributeName] = UIColor.redColor()
let dictionary: Dictionary<NSObject, AnyObject> = nsMutableDictionary
self.attributedPlaceholder = NSAttributedString(string: textParam, attributes: dictionary)
let dictionary : Dictionary = [
"key": "value",
"key2": 2,
"key3": NSString(),
2: "test",
]
One can specify types which restricts the dictionary
let dictionary : Dictionary<String, String> = [
"key": "value",
"key2": 2, // This errors
]