This is my json:
[
{
"category" : {
"id" : 1,
"text" : "cat1"
},
"id" : 1,
"title" : "book1"
},{
"category" : {
"id" : 2,
"text" : "cat2"
},
"id" : 2,
"title" : "book2"
},{
"category" : {
"id" : 1,
"text" : "cat1"
},
"id" : 3,
"title" : "book3"
}
]
How can I grouping it by category? i want to use them in different collectionView
Thank you in advance
Define your JSON codable classes as follows.
typealias Result = [ResultElement]
struct ResultElement: Codable {
let category: Category
let id: Int
let title: String
}
struct Category: Codable {
let id: Int
let text: String
}
Now, Iterate Result array after JSON parsing using JSONDecoder and compare Category struct by equal operator and group it. Since Int and String inside Category struct conforms to Equatable protocol by default, Category struct can also be compared using Equatable protocol.
You can try
let str = """
[
{
"category" : {
"id" : 1,
"text" : "cat1"
},
"id" : 1,
"title" : "book1"
},{
"category" : {
"id" : 2,
"text" : "cat2"
},
"id" : 2,
"title" : "book2"
},{
"category" : {
"id" : 1,
"text" : "cat1"
},
"id" : 3,
"title" : "book3"
}
]
"""
do {
let res = try JSONDecoder().decode([Root].self, from: Data(str.utf8))
print(res)
let dic = Dictionary(grouping: res, by: { $0.category.text})
print(dic) // this dictionary is your new data source key is title of section value is sections rows
}
catch {
print(error)
}
struct Root: Codable {
let category: Category
let id: Int
let title: String
}
struct Category: Codable {
let id: Int
let text: String
}
Create Structs
//MARK: - MyData
public struct MyData {
public var category : Category
public var id : Int
public var title : String
}
//MARK: - Category
public struct Category {
public var id : Int
public var text : String
}
Create Model
func createData () -> [MyData] {
let c1 = Category.init(id: 1, text: "Cat1")
let d1 = MyData.init(category: c1, id: 1, title: "Book1")
let c2 = Category.init(id: 2, text: "Cat2")
let d2 = MyData.init(category: c2, id: 2, title: "Book2")
let c3 = Category.init(id: 1, text: "Cat1")
let d3 = MyData.init(category: c3, id: 3, title: "Book3")
return [d1, d2, d3]
}
Group your data
let ungroupedData = createData()
print("Ungrouped\n")
print(ungroupedData)
let groupedData = Dictionary(grouping: ungroupedData, by: {$0.category.text})
print("\nGrouped\n")
print(groupedData)
groupedData["Cat1"] // get cat1 array list
Related
I have been trying to decode this Json data but I'm not able to do it completly :
This is my sample json data :
{
"id": 10644,
"name": "CP2500",
"numberOfConnectors": 2,
"connectors": [
{
"id": 59985,
"name": "CP2500 - 1",
"maxchspeed": 22.08,
"connector": 1,
"description": "AVAILABLE"
},
{
"id": 59986,
"name": "CP2500 - 2",
"maxchspeed": 22.08,
"connector": 2,
"description": "AVAILABLE"
}
]
}
this is my struct :
`
struct Root: Codable {
var id: Int
var name: String
var numberOfConnectors: Int
var connectors: [Connector]
}
struct Connector: Codable {
var id: Int
var name: String
var maxchspeed: Double
var connector: Int
var connectorDescription: String
enum CodingKeys: String, CodingKey {
case id, name, maxchspeed, connector
case connectorDescription = "description"
}
}
I want to parse the element within the [Connector] array but I'm just getting the elements of the Root level :
let jsonData = array.data(using: .utf8)!
let root = try JSONDecoder().decode(Root.self, from: jsonData)
print("\(root.id)")
Any idea how to do this ?
do {
let root = try JSONDecoder().decode(Root.self, from: jsonData)
print("root id : \(root.id)")
root.connectors.forEach {
print("name : \($0.name),"," connector id : \($0.id),","status : \($0.description)");
}
} catch {
print(error.localizedDescription)
}
Please help make this work I've been trying to figure out JSON and Swift for a week and facing this problem for 5 hours so far today.
Error Received
ERROR WHEN DECODING JSON keyNotFound(CodingKeys(stringValue: "MP", intValue: nil), Swift.DecodingError.Context(codingPath: [], debugDescription: "No value associated with key CodingKeys(stringValue: "MP", intValue: nil) ("MP").", underlyingError: nil))
YEAR IS NIL
Code
struct UserDay: Codable {
let MP: UserMP
let WP: UserWP
}
struct UserMP: Codable {
let M: [UserM]
let S: [UserS]
}
struct UserM : Codable {
let title: String
let description: String
let time: String
}
struct UserS : Codable {
let title: String
let description: String
let time: String
}
struct UserWP: Codable {
let WP: [WPData]
}
struct WPData: Codable {
let title: String
let values: [Int]
}
class LogDataHandler {
public func grabJSONInfo(){
guard let jsonURL = Bundle(for: type(of: self)).path(forResource: "newLogData", ofType: "json") else { return }
guard let jsonString = try? String(contentsOf: URL(fileURLWithPath: jsonURL), encoding: String.Encoding.utf8) else { return }
// print(jsonString)
// Print Info for TESTING
var year: UserDay?
do {
year = try JSONDecoder().decode(UserDay.self, from: Data(jsonString.utf8))
} catch {
print("ERROR WHEN DECODING JSON \(error)")
}
guard let results = year else {
print("YEAR IS NIL")
return
}
print(results)
}
}
JSON
{
"01/01/2020": {
"MP" : {
"M" : [
{"title" : "m1", "description" : "1", "time" : "12:30pm"},
{"title" : "m2", "description" : "2", "time" : "1:30pm"},
{"title" : "m3", "description" : "3", "time" : "2:30pm"}
],
"S" : [
{"title" : "s1", "description" : "1", "time" : "1pm"}
]
},
"WP" : [
{ "title" : "abc", "values" : [12, 10, 6]},
{ "title" : "def", "values" : [8]}
]
},
"01/29/2020": {
"MP" : {
"M" : [{"title" : "m1", "description" : "1", "time" : "12:30pm"}],
"S" : [{"title" : "s1", "description" : "1", "time" : "12:30pm"}]
},
"WP" :[{ "title" : "def", "values" : [8]}]
}
}
First, replace let WP: UserWP with an array:
struct UserDay: Codable {
let MP: UserMP
let WP: [WPData]
}
Then decode [String:UserDay] instead of UserDay:
try JSONDecoder().decode([String:UserDay].self, from: Data(jsonString.utf8))
Note that this will return a dict with key-value pairs "01/01/2020":UserDay object.
This means you can't assign a dictionary [String: UserDay] to a UserDay variable. Instead you can access the dict by a key which is some date (eg. "01/01/2020") and then assign it to your UserDay variable:
let result = try JSONDecoder().decode([String:UserDay].self, from: Data(jsonString.utf8))
let someYear = result["01/01/2020"]
Note that someYear will be optional so you may want to provide a default value or force-unwrap it.
I am a beginner programmer and I couldn't parse my json file. I can see datas in my console but I need help to parse json datas. I shared my json datas from url and I would like to parse with Alamofire. I installed PodFile with Alamofite and SwiftyJSON. I don't have any error but I need help for parse it.
Also I created string Arrays for following datas. I will append data in arrays.
[
{
"id" : 1,
"team" : "Liverpool",
"players" : [
{
"id" : 2,
"name" : "Alisson",
"position" : "Goal Keeper",
"number" : "13"
},
{
"id" : 3,
"name" : "Salah",
"position" : "Forward",
"number" : "10"
}
],
"trophies" : [
"2019 champions league",
"2005 champions league"
],
"logoUrl" : "url"
},
{
"id" : 4,
"team" : "Real Madrid",
"players" : [
{
"id" : 5,
"name" : "Ramos",
"position" : "Defender",
"number" : "4"
},
{
"id" : 6,
"name" : "Benzema",
"position" : "Forward",
"number" : "9"
}
],
"trophies" : [
"2018 champions league",
"2017 champions league",
"2016 champions league"
],
"logoUrl" : "url"
}
]
import Alamofire
import SwiftyJSON
func fetchJsonData(){
DispatchQueue.main.async {
Alamofire.request(url).responseData { response in
guard let data = response.data else { return }
do {
let res = try JSONDecoder().decode([PageData].self, from:data)
print(res)
} catch {
print("having trouble converting it to a dictionary" , error)
}
}
}
}
// this is my modal file
struct PageData: Codable {
let team: String
let players: [Player]
let trophies: [String]
let logoUrlL: String
}
struct Player: Codable {
let id: Int
let name,position, number: String?
}
You need responseData for using JSONDecoder
Alamofire.request(url).responseData { response in
guard let data = response.data else { return }
do {
let res = try JSONDecoder().decode([PageData].self, from:data)
print(res)
} catch {
print("having trouble converting it to a dictionary" , error)
}
}
Also players and trophies are arrays
struct PageData: Codable {
let team: String
let players: [Player]
let trophies: [String]
let logoUrlL: String
}
struct Player: Codable {
let id: Int
let name,position, number, type, quantity: String?
}
I'm using Alamofire and SwiftyJSON and I want to check if the response contains a value that I will type in a search bar.
I've just got the whole JSON file of 1666 objects and append it into my objects array and then I'm searching for value, but it takes too long.
func parseJSON(json: JSON, parse: ParseType) {
var i = 0
var j = 0
switch parse {
case .group:
for elements in json["groups"] {
if let groupId = json["groups"][i]["id"].int {
let groupName = json["groups"][i]["name"].string
// print(groupId)
let group = Groups(id: groupId, name: groupName!)
groupsArray.append(group)
i += 1
} else {
print("Error can't parse JSON")
}
}
func getGroupsData(url: String, groupName: String) {
Alamofire.request(url, method: .get).responseJSON { (response) in
if response.result.isSuccess {
print("Is Success")
let json = JSON(response.result.value)
self.parseJSON(json: json, parse: .group)
if let group = self.groupsArray.first(where: {$0.name == groupName}) {
print("found \(group)")
let searchScheduleUrl = url + "\(group.id)"
self.getGroupSchedule(url: searchScheduleUrl)
} else {
print("Can't find group")
}
} else {
print(response.result.error)
}
}
}
And here is JSON:
{
"groups" : [
{
"faculty" : {
"id" : 101,
"abbr" : "ИнГО",
"name" : "Гуманитарный институт"
},
"id" : 26262,
"spec" : "47.06.01 Философия, этика и религиоведение",
"kind" : 3,
"level" : 3,
"name" : "33865\/4702",
"type" : "common"
},
{
"faculty" : {
"id" : 95,
"abbr" : "ИКНТ",
"name" : "Институт компьютерных наук и технологий"
},
"id" : 27432,
"spec" : "09.03.04 Программная инженерия",
"kind" : 0,
"level" : 1,
"name" : "в13534\/22",
"type" : "evening"
},
{
"faculty" : {
"id" : 92,
"abbr" : "ИСИ",
"name" : "Инженерно-строительный институт"
},
"id" : 26322,
"spec" : "08.06.01 Техника и технологии строительства",
"kind" : 3,
"level" : 1,
"name" : "13163\/0801",
"type" : "common"
}, and so on...
I want to check for example:
if name: "13541/1" is in dictionary and if it is i want to get it's id
You can try
struct Root: Codable {
let groups: [Group]
}
struct Group: Codable {
let faculty: Faculty
let id: Int
let spec: String
let kind, level: Int
let name, type: String
}
struct Faculty: Codable {
let id: Int
let abbr, name: String
}
do {
let res = try JSONDecoder().decode(Root.self,from:data)
if let item = res.groups.first(where:{ $0.name == YourName }) {
print(item.id)
}
}
catch {
print(error)
}
With the json below, is it possible to get those keys under "fields" and print out one by one using for loop. (path, public_key, icon, name, description)
{
"fields" : {
"path" : { "type" : "text", "source" : "path" },
"public_key" : { "type" : "text", "source" : "public_key" },
"icon" : { "type" : "image", "source" : "icon" },
"name" : { "type" : "text", "source" : "name" },
"description" : { "type" : "text", "source" : "description" }
},
"parName" : "myapps",
"method" : 103,
"table" : "appslist",
"callBackID" : "25b4599a-eead-6f6c-894e-e4de05b1364b"
}
My object model
struct params: Decodable {
let fields: fields?
let parName: String?
let method: Int?
let table: String?
let callBackID: String?
}
struct fields: Decodable {
let name: properties?
let description: properties?
let public_key: properties?
let path: properties?
let icon: properties?
let imagelist: properties?
let templatepath: properties?
let thumbnail: properties?
}
struct properties: Decodable {
let source: String?
let type: String?
}
If you want a loop and the keys are dynamic decode the fields as [String:Properties]
First of all declare the structs with capitalized names and declare only those properties as optional which can be nil.
struct Params: Decodable {
let fields: [String:Properties]
let parName: String
let method: Int
let table: String
let callBackID: String
}
struct Properties: Decodable {
let source: String
let type: String
}
Then decode the JSON, define an array of key paths and enumerate the array (data is the Data instance representing the JSON)
do {
let result = try JSONDecoder().decode(Params.self, from: data)
let fields = result.fields
for (key, _) in result.fields {
print(key)
}
} catch {
print("error: ", error)
}