I have JSON like this:
{
"SKzSjdBuOpO49wkPVaxtmLQoR0O2": {
location: "-LB1fn5GQKTaIc-fGNPS"
},
"s0ntSZP7mBQw1a8ua0E5PqazlqJ2": {
location: "-LB23izD7bp2NhO0UuIo"
},
"FEScjelpNSR7vuVz1ha6Z6uSfF43": {
location: "-LB1JLABuJO1NyJ-v2t_"
},
"mW7dGja6cRRB0d9uSIhg4f35PzC3": {
location: "-LB5xqUvIjEgtW_FH_nG"
},
"GCnt0VKcqjT8bl2chw43nsntaZK2": {
location: "-LB1n8ga9C0vCcZXD2Us"
}
}
in my Values[String: Any] dictionary. And i want to Create another dictionary from its values to access location value.
Can you help me to do this?
If the primary goal is just to access the values and the type is fixed to [String: Any], do it like this:
if let info = dictionary["SKzSjdBuOpO49wkPVaxtmLQoR0O2"] as? [String : String] {
let location = info["location"]
}
Try not to use Dictionary in swift, rather for your case you can use [String : [String: String]] type and then loop through you data to get the required values. Try this
let dict = ["SKzSjdBuOpO49wkPVaxtmLQoR0O2": [
"location" : "-LB1fn5GQKTaIc-fGNPS",
], "s0ntSZP7mBQw1a8ua0E5PqazlqJ2": [
"location" : "-LB23izD7bp2NhO0UuIo",
], "FEScjelpNSR7vuVz1ha6Z6uSfF43": [
"location" : "-LB1JLABuJO1NyJ-v2t_",
], "mW7dGja6cRRB0d9uSIhg4f35PzC3": [
"location" : "-LB5xqUvIjEgtW_FH_nG",
], "GCnt0VKcqjT8bl2chw43nsntaZK2": [
"location" : "-LB1n8ga9C0vCcZXD2Us",
]]
var newDict = [String: String]()
for (key, val) in dict {
newDict[key] = val["location"]
}
print(newDict)
Output:
["SKzSjdBuOpO49wkPVaxtmLQoR0O2": "-LB1fn5GQKTaIc-fGNPS",
"s0ntSZP7mBQw1a8ua0E5PqazlqJ2": "-LB23izD7bp2NhO0UuIo",
"FEScjelpNSR7vuVz1ha6Z6uSfF43": "-LB1JLABuJO1NyJ-v2t_",
"mW7dGja6cRRB0d9uSIhg4f35PzC3": "-LB5xqUvIjEgtW_FH_nG",
"GCnt0VKcqjT8bl2chw43nsntaZK2": "-LB1n8ga9C0vCcZXD2Us"]
Edit
For your case as you have dictionary, you can try this:
let dict = ["SKzSjdBuOpO49wkPVaxtmLQoR0O2": [
"location" : "-LB1fn5GQKTaIc-fGNPS",
], "s0ntSZP7mBQw1a8ua0E5PqazlqJ2": [
"location" : "-LB23izD7bp2NhO0UuIo",
], "FEScjelpNSR7vuVz1ha6Z6uSfF43": [
"location" : "-LB1JLABuJO1NyJ-v2t_",
], "mW7dGja6cRRB0d9uSIhg4f35PzC3": [
"location" : "-LB5xqUvIjEgtW_FH_nG",
], "GCnt0VKcqjT8bl2chw43nsntaZK2": [
"location" : "-LB1n8ga9C0vCcZXD2Us",
]] as Dictionary<String, Any>
var newDict = [String: String]()
for (key, val) in dict {
if let value = val as? [String: String] {
newDict[key] = value["location"]
}
}
print(newDict)
Related
How to convert json into dictionary for POST api call Swift
info contains an array of object that have User and Address keys You need
let dict1 : [String:Any] = ["ID" : "User123", "Name" : "Virat", "UserID" : 0]
let dict2 : [String:Any] = ["city" : "Delhi", "pin" : 123]
let addressDict : [String:Any] = ["User" : dict1,"Address" : dict2]
let infoDict : [String:Any] = ["info" :[addressDict]]
To better understand look to
// MARK: - Empty
struct Empty: Codable {
let info: [Info]
}
// MARK: - Info
struct Info: Codable {
let user: User
let address: Address
enum CodingKeys: String, CodingKey {
case user = "User"
case address = "Address"
}
}
// MARK: - Address
struct Address: Codable {
let city: String
let pin: Int
}
// MARK: - User
struct User: Codable {
let id, name: String
let userID: Int
enum CodingKeys: String, CodingKey {
case id = "ID"
case name = "Name"
case userID = "UserID"
}
}
You can also use the models above and convert the model to Data with JSONEncodable
The issue is that you're adding user and address as separate dictionaries on the array.
The JSON you posted has an array for info key but its ONE dictionary with two keys.
You need to combine the address and user dicts into one declaration and then wrap that in an array.
For ex:
let dict1 : [String:Any] = ["ID" : "User123", "Name" : "Virat", "UserID" : 0]
let dict2 : [String:Any] = ["city" : "Delhi", "pin" : 123]
let dicts : [String:Any] = ["User": dict1, "Address" : dict2]
let arr = [dicts]
let infoDict : [String:Any] = ["info" : arr]
EDIT: I would agree with SH_Khan that a much better way of doing this would be to create a Codable model
The issue is you are make dictionary per object.
try this code:
let userDict : [String:Any] = ["ID" : "User123", "Name" : "Virat", "UserID" : 0]
let addressDict : [String:Any] = ["city" : "Delhi", "pin" : 123]
let infoDict : [String:Any] = ["info" : ["User": addressDict, "Address": addressDict]]
Try this:
func getDictionaryFromString(_ json: String) -> [String: Any]? {
if let data = json.data(using: .utf8) {
do {
return try JSONSerialization.jsonObject(with: data, options: []) as? [String: Any]
} catch {
print(error.localizedDescription)
}
}
return nil
}
override func viewDidLoad() {
super.viewDidLoad()
let json = """
{"info": [{
"User": {"ID": "user123",
"Name": "Virat",
"UserID": 0
},
"Address": {"city": "Delhi",
"pin": 123
}
}
]
}
"""
if let dict = getDictionaryFromString(json) {
print(dict["info"] as! NSArray)
}
}
//Printed:
> (
> {
> Address = {
> city = Delhi;
> pin = 123;
> };
> User = {
> ID = user123;
> Name = Virat;
> UserID = 0;
> };
> } )
On click of a submit button the data in my textfields and some other data are being converted to a json object like so…
let categoryName = self.categoryTextField.text
let categoryId = self.categoryID
let category_json: [String: [String:Any]] = [
"categoryDetails": [
"category_name": categoryName,
"category_id": categoryId
]
]
if let data = try? JSONSerialization.data(withJSONObject: category_json, options: .prettyPrinted),
let str = String(data: data, encoding: .utf8) {
print(str) // `str` gives the json object
self.categoryStrToPass = str
}
Now self.categoryStrToPass is assigned to another json object and then finally added to a string array like so…
let productID = self.prodID
let sellingPrice = self.mrpTextField.text
let categoryJSON = self.categoryStrToPass
let jsonObject: [String: [String:Any]] = [
"prodDetails": [
"product_id": productID,
"selling_price": sellingPrice,
“category_json”: categoryJSON
]
]
if let data = try? JSONSerialization.data(withJSONObject: jsonObject, options: .prettyPrinted),
let str = String(data: data, encoding: .utf8) {
print(str)
self.jsonStrToPass = str
self.jsonStringArray.append(self.jsonStrToPass)
}
Now I’m storing jsonStringArray to coredata like so…
_product?.setValue(self.jsonStringArray, forKey:
"productJsonArray") // productJsonArray is an attribute of type Transformable and Custom class type Array<String>
And it is being fetched like so...
if let jsonObjArr = result.value(forKey: "productJsonArray") as?
Array<NSString> {
print(jsonObjArr)
}
Now on 2 different instances I have submitted the data which means on printing jsonObjArr while fetching,it should have 2 different json objects in one array like so..
[{
"prodDetails" : {
"product_id" : "0",
"category_json" : "{\n \"categoryDetails\" : {\n \"category_id\" : \"0\",\n \"category_name\" : \"prodCAT\"\n }\n}",
"selling_price" : "500",
}
}
{
"prodDetails" : {
"product_id" : "1",
"category_json" : "{\n \"categoryDetails\" : {\n \"category_id\" : \"0\",\n \"category_name\" : \"CATNEW\"\n }\n}",
"selling_price" : "1000",
}
}]
But instead, printing jsonObjArr is giving this…in 2 different arrays like so...
[{
"prodDetails" : {
"product_id" : "0",
"category_json" : "{\n \"categoryDetails\" : {\n \"category_id\" : \"0\",\n \"category_name\" : \"prodCAT\"\n }\n}",
"selling_price" : "500",
}
}]
[{
"prodDetails" : {
"product_id" : "1",
"category_json" : "{\n \"categoryDetails\" : {\n \"category_id\" : \"0\",\n \"category_name\" : \"CATNEW\"\n }\n}",
"selling_price" : "1000",
}
}]
How can I get multiple json objects in one single array...?
you can add objects of type [String: Any] to array like so
let firstCategoryName = "first"
let firstCategoryId = 1
let firstCategory = [
"category_name": firstCategoryName,
"category_id": firstCategoryId
] as [String : Any]
let secondCategoryName = "second"
let secondCategoryId = 2
var category_json = [[String:Any]]()
category_json.append(firstCategory)
let secondCategory = [
"category_name": secondCategoryName,
"category_id": secondCategoryId
] as [String : Any]
category_json.append(secondCategory)
print(category_json)
then serialize the array
Swift 4.0:
let firstObj = ["prodDetails": [
"product_id": 5,
"selling_price": 6,
]]
let secondObj = ["prodDetails1": [
"product_id1": 5,
"selling_price1": 6,
]]
let jsonObject = jsonStringArray.addingObjects(from: [firstObj,secondObj])
if let data = try? JSONSerialization.data(withJSONObject: jsonObject, options: .prettyPrinted),
let str = String(data: data, encoding: .utf8) {
print(str) //prints array of dictionaries
}
category_json and jsonObject are of the same kind.
What you need to understand:
(NS)String <== String(data:encoding) or data(encoding:) ==> (NS)Data
Applied to specific String/Data: JSON:
JSON Stringified <== String(data:encoding) or data(encoding:) ==> JSON Data
Swift Array/ Swift (and the rest JSON compliant) <== (NS)JSONSerialization.jsonObject(withData:, options:) or (NS)JSONSerialization.data(withJSONObject:, options:) ==> JSON Data
You can't append like that the two JSON Stringified, you need to have an array at least at top level.
So, let's connect the dots, in pseudo code (not sure at all that the method name are error free)
let currentData = self.jsonStrToPass.data(encoding: .utf8)
let current = JSONSerialization.jsonObject(with:currentData, options:[]) as [String:[String:Any]]
let finalArray : [[String:[String:Any]]]()
finalArray.append(current)
finalArray.append(jsonObject)
let finalData = JSONSerialization.data(withJSONObject:finalArray, options:[])
let finalString = String(data:finalData, encoding:.utf8)
That's for the logic. I didn't do the if let, try/catch, etc.
I'd think it might be better to pass Any (for Swift Array/Dictionary instead of String) between your data to pass. It might be simpler to edit them (append, etc.) instead of String.
This is on XCode 7.3.
If I build the code with optimization flag -O, it will be crashed. It is working properly without optimization (flag -Onone). However I want to have my code built with optimization.
Is it Swift compiler bug?
This is the code.
import Foundation
extension Dictionary where Key: StringLiteralConvertible, Value: AnyObject {
func multipartFormParams(preFix preFix: String = "") -> [String: AnyObject] {
var params: [String: AnyObject] = [:]
for (key, value) in self {
let subKey = preFix != "" ? "\(preFix)[\(key)]" : String(key)
if let value = value as? [String: AnyObject] {
// params += value.multipartFormParams(preFix: subKey) // this is my original code, however remove the operation extension += to focus on the bug.
value.multipartFormParams(preFix: subKey) // It crash here.
} else {
params[subKey] = value
}
}
return params
}
}
let parameters: [String: AnyObject] = [
"user": [
"first_name": "first",
"last_name": "last"
]
]
parameters.multipartFormParams()
After a while, I found that this is related to this bug: https://bugs.swift.org/browse/SR-1114, change for (key, value) in self { to forEach { key, value in solved the problem.
Full working version:
import Foundation
extension Dictionary where Key: StringLiteralConvertible, Value: AnyObject {
func multipartFormParams(preFix preFix: String = "") -> [String: AnyObject] {
var params: [String: AnyObject] = [:]
forEach { key, value in
let subKey = preFix != "" ? "\(preFix)[\(key)]" : String(key)
if let value = value as? [String: AnyObject] {
// params += value.multipartFormParams(preFix: subKey) // this is my original code, however remove the operation extension += to focus on the bug.
value.multipartFormParams(preFix: subKey) // It crash here.
} else {
params[subKey] = value
}
}
return params
}
}
let parameters: [String: AnyObject] = [
"user": [
"first_name": "first",
"last_name": "last"
]
]
parameters.multipartFormParams()
I have an NSEnumerator which contains nested key value objects like this:
[ "posts" :
["randonRootKey1" :
["randomChildKey1" : [:] ]
],
["randonRootKey2" :
["randomChildKey2" : [:] ],
["randomChildKey3" : [:] ],
]
]
- posts
-- user1
--- posts
----post
-- user2
-- posts
--- post
I want to extract all posts of all users in one array ... last child and all parents are dictionaries
I want to flatMap it to be :
[
["randomChildKey1" : [:] ],
["randomChildKey2" : [:] ],
["randomChildKey3" : [:] ]
]
Note that I have extracted the objects of each root dictionary.
I have tried :
let sub = snapshot.children.flatMap({$0})
but does not seem to work
let input: [String: [String: [String: Any]]] = ["posts":
[
"randonRootKey1": [
"randomChildKey1": [:],
],
"randonRootKey2": [
"randomChildKey2": [:],
"randomChildKey3": [:],
]
]
]
var output = [String: Any]()
for dictionary in input["posts"]!.values {
for (key, value) in dictionary {
output[key] = value
}
}
print(output)
["randomChildKey3": [:], "randomChildKey2": [:], "randomChildKey1": [:]]
Assuming the input to be in this format
let input: [String: [String: [String: Any]]] = ["posts":
[
"randonRootKey1": [
"randomChildKey1": [:],
],
"randonRootKey2": [
"randomChildKey2": [:],
"randomChildKey3": [:],
]
]
]
Using this
let output = input.flatMap{$0.1}.flatMap{$0.1}
You will get the desired output
[("randomChildKey1", [:]), ("randomChildKey2", [:]), ("randomChildKey3", [:])]
If you want to convert the tuple to dictionary use reduce
let output = input.flatMap{$0.1}.flatMap{$0.1}.reduce([String: Any]())
{
(var dict, tuple) in
dict.append([tuple.0: tuple.1])
return dict
}
[["randomChildKey1": {}], ["randomChildKey2": {}], ["randomChildKey3": {}]]
I am trying to create a mixed pattern dictionary in Swift which contains either String:String or String:Dictionary as below. Can anyone help?
var tempDict = ["Electronics":"TV"],["Home":["Kitchen":"Utensils"],["BedRoom":"Bed "],["DiningRoom":"Dining"]]
I may be missing what you really want to do, but you can declare a dictionary like this:
var tempDict = ["Electronics":"TV","Home":["Kitchen":"Utensils"],"BedRoom":"Bed ","DiningRoom":"Dining"]
Swift (as of 2.2.1) infers the type of tempDict as [String: NSObject], so you can use the values with casting:
if let electronics = tempDict["Electronics"] as? String {
print(electronics)
}
if let home = tempDict["Home"] as? [String: String] {
print(home)
}
Use AnyObject:
var tempDict: [String: AnyObject] = ["Electronics":"TV"]
tempDict = ["Home":["Kitchen":"Utensils"]
["BedRoom":"Bed "],
["DiningRoom":"Dining"]]
var tempDict = [
"ElectronicsString" : "TV",
"HomeDic" : [
[
"Kitchen" : "Utensils",
"BedRoom":"Bed ",
"DiningRoom":"Dining",
]
],
"BetArray" : [
"cat",
"dog"
]
]
By the way, if a dictionary is a big compounded dictionary, the complier of Swift will have error. So you can solve it like this:
var tempDict: [String: AnyObject] = [
"ElectronicsString" : "TV"
]
tempDict["HomeDic"] = [
[
"Kitchen" : "Utensils",
"BedRoom":"Bed ",
"DiningRoom":"Dining",
]
]
tempDict["BetArray"] = [
"cat",
"dog"
]