使用java根据键值拆分JSON文件中的数据

Posted

技术标签:

【中文标题】使用java根据键值拆分JSON文件中的数据【英文标题】:Split data in JSON file based on a key value using java 【发布时间】:2022-01-20 04:28:59 【问题描述】:

我有一个 json 文件,其中有一个产品项目数组,我想根据项目的类别将它们拆分, 这是我的 json 文件的样子,


    "items":[
        
            "item-id": 123,
            "name": "Cheese",
            "price": 8,
            "category": "Dairy" 
        ,
        
            "item-id": 124,
            "name": "Milk",
            "price": 23,
            "category": "Dairy"
        ,
        
            "item-id": 125,
            "name": "Chicken",
            "price": 100,
            "category": "Meat"
        ,
        
            "item-id": 126,
            "name": "Fish",
            "price": 45,
            "category": "Meat"
        
    ]


我想像这样拆分它们,

[
    
        "category":"Dairy",
        "items":[
            
                "item-id": 123,
                "name": "Cheese",
                "price": 8,
                "category": "Dairy" 
            ,
            
                "item-id": 124,
                "name": "Milk",
                "price": 23,
                "category": "Dairy"
            
        ]
    ,
    
        "category":"Meat",
        "items":[
            
                "item-id": 125,
                "name": "Chicken",
                "price": 100,
                "category": "Meat"
            ,
            
                "item-id": 126,
                "name": "Fish",
                "price": 45,
                "category": "Meat"
            
        ]
    
]

这是我迄今为止尝试过的代码,但找不到像我想要的那样拆分它们的方法,我正在使用 java,而且我也是 java 新手

import java.io.*; 
import java.util.*;
import org.json.simple.*;
import org.json.simple.parser.*;

public class ReadOrderDetails 

    @SuppressWarnings("unused")
    public static void main(String[] args) 
        JSONParser parser = new JSONParser();
        JSONObject subOrder = new JSONObject();
        JSONArray  gitems = new JSONArray();
        JSONArray  subOrders = new JSONArray();
        
        try 
            Object obj = parser.parse(new FileReader("order-details.json"));
            JSONObject jsonObject = (JSONObject)obj;
            String orderId = (String)jsonObject.get("orderId");
            JSONArray items = (JSONArray)jsonObject.get("items");
            @SuppressWarnings("rawtypes")
            Iterator iterator = items.iterator();
            System.out.println("Order Id: " + orderId);
            while(iterator.hasNext()) 
                JSONObject item = (JSONObject)iterator.next();
                if(subOrders.isEmpty()) 
                    subOrder.put("category", item.get("category"));
                    gitems.add(item);
                    subOrder.put("items", gitems);
                    subOrders.add(subOrder);
                 else 
                    Iterator subOrdersIterator = subOrders.iterator();
                    for(int i=0; i<subOrders.size(); i++) 
                        JSONObject sitem = (JSONObject) subOrdersIterator.next();
                        if(sitem.get("category") == item.get("category")) 
                            gitems.add(item);
                            subOrder.put("items", gitems);
                            subOrders.add(subOrder);
                         else 
                            subOrder.put("category", item.get("category"));
                            gitems.add(item);
                            subOrder.put("items", gitems);
                            subOrders.add(subOrder);
                        
                    
                
                
            
         catch(Exception e) 
            e.printStackTrace();
        
        System.out.println(subOrders);
    





而且我在 java.util.ConcurrentModificationException 处遇到错误,但这不是我的主要问题,我真正想要一种方法来拆分它们我尝试了几件事没有奏效

【问题讨论】:

【参考方案1】:

一般来说,您违反了单一职责原则 (SOLID),因为您的代码一起做了两件不同的事情:解析文件和对项目进行分类。你应该分担这些责任。

其中一种方法是创建代表数据的类。假设这些类是ItemCategoryOrderCategorizedItemsOrder 是一个类,代表您的源 JSONObjectCategorizedItems - 代表您的结果 JSONArray

在这种情况下,您应该首先将文件解析为这些类,然后再将它们转换为JSONArray

代码示例:

数据类:

class Order 
    private final List<Item> items = new ArrayList<>();

    public void addItem(Item item) 
        items.add(item);
    

    public List<Item> getAllItems() 
        return new ArrayList<>(items);
    


enum Category 
    DAIRY("Dairy"),
    MEAT("Meat");

    private final String value;

    Category(String value) 
        this.value = value;
    

    public String getValue() 
        return value;
    

    public static Category of(String value) 
        for (Category category : values()) 
            if (category.value.equals(value)) 
                return category;
            
        

        throw new IllegalArgumentException("Unknown category");
    


class CategorizedItems 
    private final Category category;
    private final List<Item> items;

    public CategorizedItems(Category category, List<Item> items) 
        this.category = category;
        this.items = items;
    

    public Category getCategory() 
        return category;
    

    public List<Item> getItems() 
        return items;
    

class Item 
    private final long id;
    private final String name;
    private final long price;
    private final Category category;


    public Item(long id, String name, long price, Category category) 
        this.id = id;
        this.name = name;
        this.price = price;
        this.category = category;
    

    public long getId() 
        return id;
    

    public String getName() 
        return name;
    

    public long getPrice() 
        return price;
    

    public Category getCategory() 
        return category;
    

现在您应该在ReadOrderDetails 中编写方法,例如静态方法:

    private static JSONArray categorizedItemsToJSONArray(List<CategorizedItems> categorizedItems) 
        JSONArray jsonArray = new JSONArray();
        categorizedItems.forEach(category -> jsonArray.add(toJSONObject(category)));

        return jsonArray;
    

    private static JSONObject toJSONObject(CategorizedItems categorizedItems) 
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("category", categorizedItems.getCategory().getValue());
        jsonObject.put("items", itemsToJSONArray(categorizedItems.getItems()));

        return jsonObject;
    

    private static JSONArray itemsToJSONArray(List<Item> items) 
        JSONArray jsonArray = new JSONArray();
        items.forEach(item -> jsonArray.add(toJSONObject(item)));

        return jsonArray;
    

    private static JSONObject toJSONObject(Item item) 
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("item-id", item.getId());
        jsonObject.put("name", item.getName());
        jsonObject.put("price", item.getName());
        jsonObject.put("category", item.getCategory().getValue());

        return jsonObject;
    


    private static List<CategorizedItems> categorize(Order order) 
        List<CategorizedItems> categorizedItems = new ArrayList<>();
        for (Category category : Category.values()) 
            categorizedItems.add(
                    new CategorizedItems(
                            category,
                            order.getAllItems()
                                    .stream()
                                    .filter(item -> item.getCategory() == category)
                                    .collect(Collectors.toList())
                    )
            );
        

        return categorizedItems;
    

    private static Order orderFrom(JSONObject jsonObject) 
        JSONArray itemsJsonArray = (JSONArray) jsonObject.get("items");

        Order order = new Order();
        for (Object jsonArrayMember : itemsJsonArray) 
            JSONObject itemJsonObject = (JSONObject) jsonArrayMember;
            order.addItem(itemFrom(itemJsonObject));
        

        return order;
    

    private static Item itemFrom(JSONObject jsonObject) 
        long itemId = (Long) jsonObject.get("item-id");
        String itemName = (String) jsonObject.get("name");
        long itemPrice = (Long) jsonObject.get("price");
        Category category = Category.of((String) jsonObject.get("category"));

        return new Item(
                itemId,
                itemName,
                itemPrice,
                category
        );
    

之后,您应该执行最后一步。编写一个主函数,如:

    public static void main(String[] args) 
        JSONParser parser = new JSONParser();


        try 
            JSONObject orderJsonObject = (JSONObject) parser.parse(new FileReader("order-details.json"));
            Order order = orderFrom(orderJsonObject);
            List<CategorizedItems> categorizedItems = categorize(order);
            JSONArray categorizedItemsJsonArray = categorizedItemsToJSONArray(categorizedItems);

            // write categorizedItemsJsonArray to a file here
         catch(IOException | ParseException e) 
            throw new RuntimeException(e);
        
    

现在您的代码简单易读且清晰。您可以轻松维护它。我建议您阅读有关 SOLID 原则和代码风格的信息(我强烈推荐 Robert Martin。“清洁代码”)。这些主题将帮助您学习如何编写优雅而清晰的代码。

此外,ConcurrentModificationException 表示您在收藏方面做错了事。在您的特定情况下,我猜(不确定)问题是在您迭代 JSONArray 时对其进行了修改。只有部分 Java 集合允许。

编辑通过将整数替换为 long 来解决整数问题。

祝 Java 好运 :)

【讨论】:

得到这个错误 class java.lang.Long 不能从第一行 ``itemFrom``` 转换为 class java.lang.Integer @AbhijithEA 很有趣。我会根据这个错误按答案编辑【参考方案2】:

您不能在迭代集合时更改它。试试这个:

                Object[] subOrderArray = subOrders.toArray();
                for(Object o: subOrderArray) 
                    JSONObject sitem = (JSONObject) o;

【讨论】:

以上是关于使用java根据键值拆分JSON文件中的数据的主要内容,如果未能解决你的问题,请参考以下文章

golang 字符串转map?

Web04 Ajax

如何根据键值组将字典拆分为多个字典?

FastJson使用示例

java 怎么样获取Map中第几个键值对

根据 NSDictionary 键值将 NSArray 拆分为子数组