Stack Overflow Asked by vidalbenjoe on December 27, 2021
I would like to ask if how to group the object by another object inside its common array based on the id in Swift.
Here’s the JSON response, I need to group the list of the item by program id.
{
"id": "",
"ordered_by": 64,
"order_details": [
{
"resource": "Product",
"required_prescription": false,
"item": {
"id": 6,
"name": "Synergistic Copper Gloves",
"code": "51537661-C",
"enabled": true,
"generic_name": "Mediocre Steel Wallet",
"price_cents": 200000
},
"program": {
"id": 12, <----PROGRAM ID
"name": "Synergistic Wooden Shoes",
"provider": "Synergistic Rubber Coat",
"discount_type": "fixed"
}
},
{
"resource": "Product",
"required_prescription": true,
"item": {
"id": 7,
"name": "Rustic Leather Table",
"code": "74283131-P",
"enabled": true,
"generic_name": "Incredible Bronze Clock",
"price_cents": 8994
},
"program": {
"id": 12, <----PROGRAM ID
"name": "Synergistic Wooden Shoes",
"provider": "Synergistic Rubber Coat",
"discount_type": "fixed"
}
},
{
"resource": "Product",
"required_prescription": false,
"item": {
"id": 116,
"name": "Ergonomic Marble Hat",
"code": "98845056-A",
"enabled": true,
"generic_name": "Incredible Granite Lamp",
"price_cents": 8267
},
"program": {
"id": 10, <----PROGRAM ID
"name": "Durable Rubber Bag",
"provider": "Aerodynamic Steel Chair",
"discount_type": "fixed"
}
}
]}
For example, the item with program id 12 should be inserted under its common program.
This should be the expected object after grouping. The item was grouped by program id 12 & 10.
[
{
"id": 12, <----- PROGRAM ID
"name": "Synergistic Wooden Shoes",
"provider": "Synergistic Rubber Coat",
"discount_type": "fixed",
"item": [
{
"id": 6,
"name": "Synergistic Copper Gloves",
"code": "51537661-C",
"enabled": true,
"generic_name": "Mediocre Steel Wallet",
"price_cents": 200000
},
{
"id": 7,
"name": "Rustic Leather Table",
"code": "74283131-P",
"enabled": true,
"generic_name": "Incredible Bronze Clock",
"price_cents": 8994
}
]
},
{
"id": 10, <----PROGRAM ID
"name": "Durable Rubber Bag",
"provider": "Aerodynamic Steel Chair",
"discount_type": "fixed",
"item": [
{
"id": 116,
"name": "Ergonomic Marble Hat",
"code": "98845056-A",
"enabled": true,
"generic_name": "Incredible Granite Lamp",
"price_cents": 8267
}
]
}
]
I’ve successfully made it in Java using the sample code below:
private String parseJson(String source) {
JSONArray result = new JSONArray();
List<Integer> ids = new ArrayList<>();
HashMap<Integer,JSONObject> programs = new HashMap<>();
try {
JSONObject jSource = new JSONObject(source);
JSONArray orderDetails = jSource.getJSONArray("order_details");
if (orderDetails.length() > 0) {
for (int i = 0; i < orderDetails.length(); i++) {
JSONObject jsonObject = orderDetails.getJSONObject(i);
JSONObject item = jsonObject.getJSONObject("item");
JSONObject program = jsonObject.getJSONObject("program");
int programId = jsonObject.getJSONObject("program").getInt("id");
if (!ids.contains(programId)) {
ids.add(programId);
program.put("item",new JSONArray().put(item));
programs.put(programId,program);
}else{
program.put("item",programs.get(programId).getJSONArray("item").put(item));
}
}
for(int k :programs.keySet()){
result.put(programs.get(k));
}
}
} catch (Exception e) {
e.printStackTrace();
}
return result.toString();
}
I’m trying to replicate it on swift but I’m looking for a different approach, not the same approach as I did in Java. I tried to used reduce and filter method but it doesn’t work.
Any answer would be hight appreciated.
Thanks
I was able to group the JSON based on its common program id by creating another model ProgramWith items.
struct ProgramWithItems: Codable {
let id: Int?
let name: String?
let provider: String?
let discountType: String?
let resource: String?
let discount: String?
let item: [Item]
}
Then I used the reduce method and populate the ProgramWithItems model using the code below:
func groupItems(_ response: CartEntity.Response) -> [ProgramWithItems] {
response.orderDetails!.reduce(into: []) { (result: inout [ProgramWithItems], detail: OrderDetail) in
guard let index = result.firstIndex(where: { $0.id == detail.program?.id }) else {
var item = detail.item
item?.quantity = detail.quantity
item?.costCents = detail.cost_cents
let newProgram = ProgramWithItems(
id: detail.program?.id,
name: detail.program?.name ?? "",
provider: detail.program?.provider ?? "",
discountType: detail.program?.discountType ?? "",
resource: detail.resource ?? "",
discount: detail.program?.discount,
item: [item!])
result.append(newProgram)
return
}
let existingProgram = result[index]
var item = detail.item
item?.quantity = detail.quantity
item?.costCents = detail.cost_cents
let extendedProgram = ProgramWithItems(
id: existingProgram.id,
name: existingProgram.name,
provider: existingProgram.provider,
discountType: existingProgram.discountType,
resource: detail.resource ?? "",
discount: detail.program?.discount,
item: existingProgram.item + [item!])
result[index] = extendedProgram
}
}
Answered by vidalbenjoe on December 27, 2021
Few comments on an answer from @omerfarukozturk,
So I have applied some other logic.
Bind data with model
let arrDetails = //Bind data with model, response.orderDetails
Get Unique program ID
let arrProgramID = arrDetails.compactMap{ $0.program }.removingDuplicates(byKey: .id)
// removingDuplicates is logic for remove duplicate programs and have unique program array with all information
Bind array in [[Program: [Item]]] form
let finalArray = arrProgram.map { (program) -> [Program: [Item]] in
let arr = arrDetails.filter{ $0.program.id == program.id }.compactMap{ $0.item }
return [program: arr]
}
Adding extension for removing duplicates
extension Array {
func removingDuplicates<T: Equatable>(byKey key: KeyPath<Element, T>) -> [Element] {
var result = [Element]()
var seen = [T]()
for value in self {
let key = value[keyPath: key]
if !seen.contains(key) {
seen.append(key)
result.append(value)
}
}
return result
}
}
Answered by Bhavin Vaghela on December 27, 2021
You can use Dictionary(grouping:)
to group a list. Not completely answer, but for your case you can create a logic like below;
Assume you have a decoded response model as response
for your json.
let flatttenOrderDetails = response.order_details.flatMap( { $0 })
let grouped = Dictionary(grouping: flatttenOrderDetails, by: { (element: Detail) in
return element.program.id
})
Answered by Ömer Faruk Öztürk on December 27, 2021
Get help from others!
Recent Answers
Recent Questions
© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP