首页 > 解决方案 > JAVA - 按多个值对 Json 数组进行排序,同时保留先前的排序顺序

问题描述

我有这个 json,我希望能够按不同类型的多个字段值对其进行排序,同时保留以前的排序顺序。

  {
    "code": "1603",
    "description": "",
    "score": 10,
    "max": 100,
    "effts": "2021-12-07T00:00:00",
    "expDate": "2021-06-21",
    "charityMaxCount": 1400000,
    "charityUseCount": 938297,
    "title": "",
    "imageUrl": "",
    "status": "INACTIVE"
  },
  {
    "code": "1604",
    "description": "",
    "score": 10,
    "max": 100,
    "effts": "2020-12-07T00:00:00",
    "expDate": "2021-06-21",
    "charityMaxCount": 1400000,
    "charityUseCount": 938297,
    "title": "",
    "imageUrl": "",
    "status": "INACTIVE"
  },
  {
    "code": "1600",
    "description": "",
    "score": 10,
    "max": 100,
    "effts": "2021-12-07T00:00:00",
    "expDate": "2021-06-21",
    "charityMaxCount": 1400000,
    "charityUseCount": 938297,
    "title": "",
    "imageUrl": "",
    "status": "ACTIVE"
  },
  {
    "code": "1606",
    "description": "",
    "score": 10,
    "max": 100,
    "effts": "2022-12-07T00:00:00",
    "expDate": "2021-06-21",
    "charityMaxCount": 1400000,
    "charityUseCount": 938297,
    "title": "",
    "imageUrl": "",
    "status": "ACTIVE"
  },
  {
    "code": "1601",
    "description": "",
    "score": 10,
    "max": 100,
    "effts": "2020-12-07T00:00:00",
    "expDate": "2021-06-21",
    "charityMaxCount": 1400000,
    "charityUseCount": 938297,
    "title": "",
    "imageUrl": "",
    "status": "ACTIVE"
  }
]

我应该决定对其进行排序的字段是通过另一个 json 给出的:

  {
    "id": 1,
    "field": "status",
    "type": "string",
    "sortMode": "ASC"
  },
  {
    "id": 2,
    "field": "expDate",
    "type": "string",
    "sortMode": "ASC"
  }
]

我设法通过将 json 数组转换为列表Hashmap<String,Object> 并编写了一个自定义比较器来实现这一点。问题是,当我按 ASC 顺序按状态排序时,ACTIVE条目置于顶部时,我不希望当我选择按另一个字段(例如expDate )对其进行排序时,此顺序会变得混乱。

这是我的代码:

    public String sort() throws JsonProcessingException {
        List<TreeMap<String, String>> sortOrder = readSortOrder(sortOrderJson);
        List<HashMap<String, Object>> payLoad = readPayLoad(payloadJson);
        ObjectMapper objectMapper = new ObjectMapper();
        if (sortOrder.size() > 1) {
            for (TreeMap<String, String> map : sortOrder) {
                if (map.get(Constants.SORT_MODE).equals(SortOrder.DSC.toString())) {
                    payLoad.sort(new MapComparator(map.get(Constants.FIELD)).reversed());
                } else {
                    payLoad.sort(new MapComparator(map.get(Constants.FIELD)));
                }
            }
        }
        return objectMapper.writeValueAsString(payLoad);
    }

    public List<HashMap<String, Object>> readPayLoad(String jsonInput) {
        ObjectMapper mapper = new ObjectMapper();
        List<HashMap<String, Object>> jsonList = new ArrayList<>();
        try {
            HashMap[] payLoadDTOS = mapper.readValue(jsonInput, HashMap[].class);
            jsonList = Arrays.asList(payLoadDTOS);
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }
        return jsonList;
    }

    public List<TreeMap<String, String>> readSortOrder(String sortOrder) {
        final ObjectMapper objectMapper = new ObjectMapper();
        List<TreeMap<String, String>> jsonList = new ArrayList<>();
        try {
            TreeMap[] sortOrderDTOS = objectMapper.readValue(sortOrder, TreeMap[].class);
            jsonList = Arrays.asList(sortOrderDTOS);
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }
        return jsonList;
    }

这作为比较器:

public class MapComparator implements Comparator<Map<String, Object>> {

    private final String key;


    public MapComparator(String key) {
        this.key = key;
    }


    @Override
    public int compare(Map<String, Object> one, Map<String, Object> two) {
        Object first = one.get(key);
        Object second = two.get(key);
        if (first instanceof String && second instanceof String) {
            if ((isValidDate((String) first) && isValidDate((String) second))
                    || (isValidDateTime((String) first) && isValidDateTime((String) second))) {
                return DateTimeComparator.getInstance().compare(first, second);
            } else {
                return ((String) first).compareTo((String) second);
            }
        } else if (first instanceof Integer && second instanceof Integer) {
            return ((Integer) first).compareTo((Integer) second);
        }
        return 0;
    }
}

我认为我应该在另外两个集合中分别说ACTIVEINACTIVE并对其进行排序,但是我可以进行分离的字段可能是动态的,并且每次都可能发生变化。我怎样才能在算法上处理这个?

标签: javajsonsorting

解决方案


在相同值条目上保留现有顺序的排序算法称为stable。在 Java 中,您可以查询 API 是否保证给定的排序函数是稳定的,例如 Arrays.sort

使用多个键进行排序的典型方法是使用稳定的排序算法以键的相反顺序对条目进行顺序排序。

例如,如果您想先按名字排序,然后按姓氏排序,您将首先按姓氏排序,然后按名字排序。

您还需要确保您使用的数据结构保留了插入顺序,例如 Set 或 Map 可能不会保留该顺序。


推荐阅读