Java中基于Comparator按特定规则实现对象列表排序的技术求助
解决Java对象列表的自定义排序需求
Hey there! Let's break down how to implement your custom sorting rules step by step. First, let's recap your requirements to make sure we cover everything:
- Group pairs of objects where one's
partIdmatches the other'sid - Move all objects with
partId == nullto the end of the list - Sort the groups by
countwith two priorities:- First prioritize groups where both
countvalues are smaller - Then prioritize groups where at least one
countis smaller than other groups
- First prioritize groups where both
Step 1: Define the Entity Class
First, let's assume your object is an Item class with the required fields (adjust if your actual class differs):
class Item { private Long id; private Long partId; private Integer count; // Constructor, getters, toString public Item(Long id, Long partId, Integer count) { this.id = id; this.partId = partId; this.count = count; } public Long getId() { return id; } public Long getPartId() { return partId; } public Integer getCount() { return count; } @Override public String toString() { return "Item{id=" + id + ", partId=" + partId + ", count=" + count + "}"; } }
Step 2: Implement the Sorting Logic
Instead of trying to handle everything in a single Comparator (which would get messy), we'll split the process into manageable steps:
- Separate Null and Non-Null
partIdItems: First, we split the list to easily move nullpartIditems to the end later. - Group Pairing Items: We find pairs where one's
partIdmatches the other'sid, marking processed items to avoid duplicates. - Sort the Groups: We sort groups using your priority rules: compare the smallest
countfirst, then the largestcountin each group. - Sort Within Groups: Each group's elements are sorted by
countin ascending order. - Merge Lists: Combine the sorted non-null groups with the null
partIditems (added to the end).
Here's the full implementation:
import java.util.*; import java.util.stream.Collectors; public class ListTTest { public static void main(String[] args) { // Test data - adjust to match your actual objects List<Item> items = Arrays.asList( new Item(1L, 2L, 3), new Item(2L, 1L, 2), new Item(3L, 4L, 1), new Item(4L, 3L, 4), new Item(5L, null, 5), new Item(6L, 7L, 2), new Item(7L, 6L, 1), new Item(8L, null, 0) ); // 1. Split items into non-null partId and null partId lists Map<Boolean, List<Item>> splitItems = items.stream() .collect(Collectors.partitioningBy(item -> item.getPartId() == null)); List<Item> nonNullPartIdItems = splitItems.get(false); List<Item> nullPartIdItems = splitItems.get(true); // 2. Group paired items (partId matches another item's id) Set<Long> processedIds = new HashSet<>(); List<List<Item>> groups = new ArrayList<>(); for (Item item : nonNullPartIdItems) { if (processedIds.contains(item.getId())) continue; // Find the matching pair Optional<Item> pairOpt = nonNullPartIdItems.stream() .filter(pair -> !processedIds.contains(pair.getId()) && (Objects.equals(item.getPartId(), pair.getId()) || Objects.equals(pair.getPartId(), item.getId()))) .findFirst(); if (pairOpt.isPresent()) { Item pair = pairOpt.get(); groups.add(Arrays.asList(item, pair)); processedIds.add(item.getId()); processedIds.add(pair.getId()); } else { // Handle unpaired items (if any) by adding them as single-item groups groups.add(Collections.singletonList(item)); processedIds.add(item.getId()); } } // 3. Sort groups by your priority rules groups.sort((group1, group2) -> { // Get sorted count lists for easy comparison List<Integer> counts1 = group1.stream().map(Item::getCount).sorted().toList(); List<Integer> counts2 = group2.stream().map(Item::getCount).sorted().toList(); // Priority 1: Compare smallest count first int minCountCompare = counts1.get(0).compareTo(counts2.get(0)); if (minCountCompare != 0) { return minCountCompare; } // Priority 2: Compare largest count if smallest counts are equal int maxCount1 = counts1.size() > 1 ? counts1.get(1) : counts1.get(0); int maxCount2 = counts2.size() > 1 ? counts2.get(1) : counts2.get(0); return Integer.compare(maxCount1, maxCount2); }); // 4. Sort elements within each group and flatten the groups List<Item> sortedNonNullItems = groups.stream() .flatMap(group -> { group.sort(Comparator.comparingInt(Item::getCount)); return group.stream(); }) .collect(Collectors.toList()); // 5. Merge sorted non-null items with null partId items (at the end) List<Item> finalSortedList = new ArrayList<>(sortedNonNullItems); finalSortedList.addAll(nullPartIdItems); // Print the result System.out.println("Final Sorted List:"); finalSortedList.forEach(System.out::println); } }
Key Explanations
- Grouping: We use a
HashSetto track processed IDs so we don't create duplicate groups. - Group Sorting: By sorting each group's
countvalues, we can easily compare the smallest and largest values to meet your priority rules. For example, a group with counts[1,2]will come before[1,3](since the largest count is smaller), and[1,4]comes before[2,3](since the smallest count is smaller). - Null Handling: Separating null
partIditems first makes it trivial to append them to the end of the sorted list.
When you run this code, the output will match your requirements: paired groups sorted by the count priorities, with all null partId items at the end.
内容的提问来源于stack exchange,提问作者cattyWashington
相关产品推荐
相关产品推荐

