How to transform JSON structure to an new array using Swift?
Initial JSON
{
"group1": {
"1/30/21": 100,
"1/31/21": 200
},
"group2": {
"1/30/21": 200,
"1/31/21": 300
},
"group3": {
"1/30/21": 300,
"1/31/21": 500
}
}
The array I'd like to convert would be like:
[
{
"group1": 100,
"group2": 200,
"group3": 300,
"date": "1/30/21",
},
{
"group1": 200,
"group2": 300,
"group3": 500,
"date": "1/31/21",
}
]
First use JSONSerialization to convert the json to a dictionary
let dictionary = try JSONSerialization.jsonObject(with: jsonIn.data(using: .utf8)!) as! [String: [String: Int]]
Then in two steps convert to the expected format by first creating a dictionary where the date is the key and groups and numbers (as a tuples) are the values
var temp = [String: [(String, Int)]]()
dictionary.forEach { key, value in
for (innerKey, innerValue) in value {
temp[innerKey, default: []].append((key, innerValue))
}
}
Then use this dictionary to create the array of dictionaries
let output = temp.map { (key, tuples) -> [String: Any] in
var result = [String: Any]()
for tuple in tuples {
result[tuple.0] = tuple.1
}
result["date"] = key
return result
}
and then back to json
let jsonOut = try JSONSerialization.data(withJSONObject: output)
Related
I have a data as given below:
[["-MXpvzmZdbqzrjND8w9F": {
lid = "-MW6eEidZFCLeeZ0uBk1";
message = hi;
timeStamp = 1617960107264;
title = "Sambhar Dosa";
user = 1QSU0c1q8QNrZzmICXGClC0o86E3;
}, "-MXq5NAyrkk4ZcvRFM7T": {
lid = "-MW6eEidZFCLeeZ0uBk1";
message = "how ru?";
timeStamp = 1617962828647;
title = "Sambhar Dosa";
user = 1QSU0c1q8QNrZzmICXGClC0o86E3;
}], ["-MXqa5-pkC28lY_Q_hpZ": {
lid = "-MWwEpHAhIdhN0i5sltB";
message = "hi nice cycle";
timeStamp = 1617971142820;
title = "Cycle for kids";
user = 1QSU0c1q8QNrZzmICXGClC0o86E3;
}]]
Now this value is defined by the variable testarray. Name given just for convenience.
The testarray is var testArray = [String: [String: Any]]
Inner dictionary is defined using a struct as given below:
struct SomeData1
{
let dict: [String: Any]
var lid: String? { dict["lid"] as? String }
var message: String? { dict["message"] as? String }
var timeStamp: Double { dict["timeStamp"] as? Double ?? 0.0 }
var title: String? { dict["title"] as? String }
var user: String? { dict["user"] as? String }
var owner: String? { dict["owner"] as? String }
}
So testarray can also be read as var testArray = [String: [SomeData1]]
Now as per the above data,when the lid matches with a particular value,then only those data is stored in a variable called dataToDisplay which is defined as var dataToDisplay = SomeData1
I have filtered the above data using the below code
var sortStep1 = self.testArray.map {
dict in dict.map {
($0.key, SomeData1(dict: $0.value))
}.filter {$0.1.lid == self.listid}
}
print("sortStep1 is",sortStep1)
the value displayed for sortStep1 is
[[("-MY5aPJ--Xoot_wlGSqS", Hungry.ChatVC.SomeData1(dict: ["owner": bPqDIJvYX7g7ZhE8ap0TgeYMYjE2, "lid": -MW6eEidZFCLeeZ0uBk1, "user": 1QSU0c1q8QNrZzmICXGClC0o86E3, "timeStamp": 1618239661393, "message": hi, "title": Sambhar Dosa])), ("-MY5b-WT4AoWWa7c1eQT", Hungry.ChatVC.SomeData1(dict: ["title": Sambhar Dosa, "message": nice product, "user": 1QSU0c1q8QNrZzmICXGClC0o86E3, "timeStamp": 1618239817904, "lid": -MW6eEidZFCLeeZ0uBk1, "owner": bPqDIJvYX7g7ZhE8ap0TgeYMYjE2]))], []]
Here there is a null array which is also shown.i do not want this null array.i want only matching list to be displayed.
Is the code for fetching matched lid correct?
I Have a Dictionary Data:
let dict: [String: Any] = [
"shapeIDs": [1,2,3],
"rows": [1,2],
"userID": "231"
]
I want to convert it in query params for URL. My Expect Result should be this:
"?shapeIDs[]=1&shapeIDs[]=2&shapeIDs[]=3&rows[]=1&rows[]=2&userID=231"
Please help to create an optimistic logic for this.
Swift Solution:
extension Dictionary {
var queryString: String {
let query = self.reduce("") { (result, keyValue) -> String in
var string = ""
if let values = keyValue.value as? Array<Any> {
string = values.map({"\(keyValue.key)[]=\($0)&"}).reduce("", +)
} else {
string = "\(keyValue.key)=\(keyValue.value)&"
}
return result + string
}.dropLast()
return "?" + String(query)
}
}
using swift vapor and elasticsearch, got a response like:
{
"_shards": {
"failed": 0,
"successful": 5,
"total": 5
},
"hits": {
"hits": [
{
"_id": "3",
"_index": "items_v1",
"_score": 1.2029922,
"_source": {
"property1": "test",
"property2": "another test",
...
},
"_type": "item"
},
...
inside "hits" -> "hits" -> "_source" I got all the properties of my model "Item". How can I create an array of Items "[Item]" from this json response?
Small enhancement, use a guard statement to avoid the nested ifs...
guard
let dict = response as? [String : Any],
let hits = dict["hits"] as? [String : Any],
let hitArray = hits["hits"] as? [[String : Any]]
else
{ throw Abort}
for hit in hitArray {
if let source = hit["_source"] {
arrayOfItems.append(Item(with: source))
}
}
Parse your response in this way, so there will be no crashes if some value will not be sent.
if let dict = response as? [String : Any] {
if let hits = dict["hits"] as? [String : Any] {
if let hitArray = hits["hits"] as? [[String : Any]] {
for hit in hitArray {
if let source = hit["_source"] {
arrayOfItems.append(Item(with: source))
}
}
}
}
}
Int your Item class create init method, where you will initialize item's properties.
init(with dict: [String : Any]) {
if let property1 = dict["property1"] as? Int {
self.property1 = property1
}
super.init()
}
Try like this! I assume that you get the Response and that response in saved in response variable
var myarray = [String]()
let hitDict = response["hits"] as! [String:AnyObject]
let hitArray = hitDict["hits"] as! Array
let someDict = hitArray[0] as! [String:AnyObject]
let sourcDict = someDict["_source"] as! [String:AnyObject]
let property1 = sourcDict["property1"] as! String
let property2 = sourcDict["property2"] as! String
myarray.append(property1)
myarray.append(property2)
var myArray = [String:String]()
//response from try drop.client.get(…)
let bodyReceived = responseFirebaseAssigned?.body.bytes
//JSON object made of bodyReceived
let JsonFirebase:JSON?
for val in JsonFirebase?.object ?? [:]{
let valKey = val.key.string
let valValue = val.value.string
arrayFB[valKey!] = valValue
print("arrayFB is \(arrayFB)")
}
Please find error location in the below image :
The number of values in tripOption will change in each request.
There a logic problem in the code where the tripOption for example outputs just 2 values.. but the loop keeps going and says array out of index.. i have no idea how to fix this issue.
var arrayOfFlights : [FlightDataModel] = [FlightDataModel]()
if json != nil {
//insert airline data into arrayOfFlights
if let myJSON = json as? [String:AnyObject] {
if let trips = myJSON["trips"] as? [String:AnyObject] {
if let data = trips["data"] as? [String:AnyObject] {
if let carriers = data["carrier"] as? [[String:String]] {
for (index, carrierName) in enumerate(carriers) {
var myFlight = FlightDataModel(airline: carrierName["name"] as String!, price:nil)
self.arrayOfFlights.append(myFlight)
println("\(self.arrayOfFlights[index].airline!)")
}
}
}
if var tripOptions = trips["tripOption"] as? [[String:String]] {
for (index, tripOption) in enumerate(tripOptions) {
self.arrayOfFlights[index].price = tripOption["saleTotal"] as String!
println("price \(self.arrayOfFlights[index].price!)")
}
}
}
}
parameteers in url jsjon request:
var parameters = [
"request": [
"slice": [
[
"origin": from,
"destination": to,
"date": when
]
],
"passengers": [
"adultCount": 1,
"infantInLapCount": 0,
"infantInSeatCount": 0,
"childCount": 0,
"seniorCount": 0
],
"solutions": 5,
"refundable": false
]
]
The error is because you are trying to access an element in arrayOfFlights with an index greater than its size - 1.
// index > no of existing elements in the array
self.arrayOfFlights[index].price = tripOption["saleTotal"] as String!
Maybe you are trying to push new elements into an empty array?
self.arrayOfFlightPrices.append(tripOption["saleTotal"] as String!)
You should simplify your code and perhaps use the first iteration of the results to ensure you don't go out of bounds. Something LIKE this:
var arrayOfFlights : [FlightDataModel] = [FlightDataModel]()
if let data = json as? NSDictionary {
if let carriers = data.valueForKeyPath("trips.data.carrier") as? NSArray {
for (index, carrier) in enumerate(carriers) {
var myFlight = FlightDataModel(airline: carrier["name"] as String!, price:nil)
arrayOfFlights.append(myFlight)
}
}
if let trips = data.valueForKey("trips") as? NSArray where arrayOfFlights.count > 0 {
for (index, carrier) in enumerate(arrayOfFlights) {
carrier.price = trips.objectAtIndex(index)["saleTotal"] as String!
}
}
}
I have an array of AnyObject objects in Swift (eventually, this array will be populated by querying a Parse database). Each object in the array has attributes of a publication, such as fullTitle, url, and journal. How can I filter the array to select all objects that match the search string for any value (e.g. where the fullTitle, url, or journal include "Forbes")?
Below is example code from a playground. First the sample array:
var publication1 = [
"fullTitle": "My first blog",
"url": "www.forbes.com/post1",
"journal": "Forbes
]
var publication2 = [
"fullTitle": "My second blog",
"url": "www.wsj.com/post1",
"journal": "Wall Street Journal"
]
var publications: [AnyObject] = [publication1, publication2]
Then, the filter function:
func filterContentForSearchText(searchText: String) {
let filteredPublications = publications.filter() {
if let fullTitle = ($0)["fullTitle"] as? String {
return fullTitle.rangeOfString(searchText) != nil
} else {
return false
}
}
}
Now, if I call the function with "first" as an argument, it should return the first object out of the array:
println(filterContentForSearchText("first"))
However, this command gives no result. How can I fix this? Also, how can I query all fields of the object for the searchText, not just the fullTitle field?
Thank you.
Here's a simple example that returns an array of matches in all fields:
func filterContentForSearchTextInAllFields(searchText: String) -> [String] {
var results = [String]()
for publication in publications {
for (key, value) in publication {
if (value as NSString).containsString(searchText) {
results.append(value)
}
}
}
return results
}
println(filterContentForSearchTextInAllFields("blog"))
This one only works on titles:
func filterContentForSearchText(searchText: String) -> [String] {
var results = [String]()
for publication in publications {
if let fullTitle = publication["fullTitle"] {
if (fullTitle as NSString).containsString(searchText) {
results.append(fullTitle)
}
}
}
return results
}
println(filterContentForSearchText("first"))
UPDATE
Here's a version for what you've asked in the comments:
func filterContentForSearchText(searchText: String) -> [[String:String]] {
var results = [[String:String]]()
for publication in publications {
if let fullTitle = publication["fullTitle"] as? String {
if (fullTitle as NSString).containsString(searchText) {
results.append(publication as! [String : String])
}
}
}
return results
}
println(filterContentForSearchText("first"))
Your "rows" are dictionaries: in the loop we assign each one to the "publication" variable, so we just take the one whose title matches the search terms then append it to an array of dictionaries.
Here is the route I went. Instead of an array of AnyObject I just let Swift infer the type
var publications = [publication1, publication2]
func searchPublications(seachText: String) -> [[String: String]] {
let filteredPublications = publications.filter { $0
for (_, value) in $0 {
if let found = value.rangeOfString(seachText, options: NSStringCompareOptions.CaseInsensitiveSearch, range: Range<String.Index>(start: value.startIndex, end: value.endIndex), locale: NSLocale.currentLocale()) {
return true
}
}
return false
}
return filteredPublications
}
Swift 3.0
This is worked for me.
I want filter data by it's status 0 or 1.
var arrRooms:[[String:AnyObject]] = [
[
"id": 30 as AnyObject,
"name": "Earth" as AnyObject,
"status": 0 as AnyObject,
"duration": 10 as AnyObject
],
[
"id": 27 as AnyObject,
"name": "Mars" as AnyObject,
"status": 1 as AnyObject,
"duration": 0 as AnyObject
]
]
let StatusPredicate = NSPredicate(format: "status = 1 ")
let arrFilter:[[String:AnyObject]] = (arrRooms as NSArray).filtered(using: StatusPredicate) as! [[String : AnyObject]]
print(arrFilter);
// output [["name": Mars, "status": 1, "id": 27, "duration": 0]]
it may be useful.thanks