Java中如何根据对象字段过滤并合并ArrayList分组数据?
Alright, let's tackle your problem step by step. First, we'll solve the specific grouping and merging task you've described, then dive into the general approach for filtering and grouping ArrayLists in Java.
Step 1: Define the Data Class
First, let's create a clean POJO (Plain Old Java Object) to represent each element in your list. I've adjusted field names to follow Java conventions (since class is a reserved keyword and class_id doesn't match camelCase):
import java.util.Objects; public class TeacherClass { private String classId; private String className; private String section; private String subject; // Constructor public TeacherClass(String classId, String className, String section, String subject) { this.classId = classId; this.className = className; this.section = section; this.subject = subject; } // Getters and Setters public String getClassId() { return classId; } public void setClassId(String classId) { this.classId = classId; } public String getClassName() { return className; } public void setClassName(String className) { this.className = className; } public String getSection() { return section; } public void setSection(String section) { this.section = section; } public String getSubject() { return subject; } public void setSubject(String subject) { this.subject = subject; } @Override public String toString() { return "TeacherClass{" + "classId='" + classId + '\'' + ", className='" + className + '\'' + ", section='" + section + '\'' + ", subject='" + subject + '\'' + '}'; } }
Step 2: Implement the Grouping & Merging Logic
Using Java 8+ Stream API (the most concise modern approach), we can group elements by className and section, then merge their subject fields:
import java.util.ArrayList; import java.util.List; import java.util.stream.Collectors; public class ClassGroupingDemo { public static void main(String[] args) { // Initialize your original list List<TeacherClass> originalList = new ArrayList<>(); originalList.add(new TeacherClass("2", "3", "A", "English")); originalList.add(new TeacherClass("1", "2", "A", "Math")); originalList.add(new TeacherClass("1", "2", "A", "Science")); // Group and merge List<TeacherClass> groupedList = originalList.stream() // Group by composite key (className + section) to avoid collisions .collect(Collectors.groupingBy( tc -> tc.getClassName() + "|" + tc.getSection(), Collectors.toList() )) .values() .stream() // Merge each group into a single TeacherClass .map(group -> { TeacherClass firstItem = group.get(0); String mergedSubjects = group.stream() .map(TeacherClass::getSubject) .collect(Collectors.joining(", ")); return new TeacherClass( firstItem.getClassId(), firstItem.getClassName(), firstItem.getSection(), mergedSubjects ); }) .collect(Collectors.toList()); // Print the final result groupedList.forEach(System.out::println); } }
How this works:
- Grouping: We use
Collectors.groupingBy()with a composite key (combiningclassNameandsectionwith a unique separator) to cluster matching elements. - Merging: For each group, we take the first element's core fields (
classId,className,section) and join allsubjectvalues into a single comma-separated string. - Collecting: Convert the grouped values back into a
List<TeacherClass>matching your desired output structure.
General Approach to Filter & Group ArrayLists in Java
There are two primary ways to handle this, depending on your Java version:
1. Stream API (Java 8+, Recommended)
The Stream API offers a declarative, readable way to process collections. Here's a reusable template:
List<YourObject> processList(List<YourObject> originalList) { return originalList.stream() // Optional: Filter elements first (e.g., exclude nulls or invalid entries) .filter(obj -> obj.getSomeField() != null) // Group by your custom key (single field or composite) .collect(Collectors.groupingBy( obj -> /* Key logic, e.g., obj.getField1() + "|" + obj.getField2() */, Collectors.toList() )) .values() .stream() // Transform groups into your desired output objects .map(group -> { YourObject template = group.get(0); String mergedField = group.stream() .map(YourObject::getFieldToMerge) .collect(Collectors.joining(", ")); return new YourObject( template.getField1(), template.getField2(), mergedField ); }) .collect(Collectors.toList()); }
For more robust composite keys, create a dedicated GroupKey class with properly overridden equals() and hashCode() methods instead of string concatenation:
class GroupKey { private final String className; private final String section; public GroupKey(String className, String section) { this.className = className; this.section = section; } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; GroupKey groupKey = (GroupKey) o; return Objects.equals(className, groupKey.className) && Objects.equals(section, groupKey.section); } @Override public int hashCode() { return Objects.hash(className, section); } }
Then use it in grouping:
Collectors.groupingBy(tc -> new GroupKey(tc.getClassName(), tc.getSection()), Collectors.toList())
2. Traditional Loops (Java < 8)
If you're stuck with an older Java version, use a Map to manually group elements:
List<TeacherClass> processListLegacy(List<TeacherClass> originalList) { Map<String, List<TeacherClass>> groupMap = new HashMap<>(); // Manual grouping for (TeacherClass tc : originalList) { String key = tc.getClassName() + "|" + tc.getSection(); groupMap.computeIfAbsent(key, k -> new ArrayList<>()).add(tc); } // Merge groups List<TeacherClass> groupedList = new ArrayList<>(); for (List<TeacherClass> group : groupMap.values()) { TeacherClass template = group.get(0); StringBuilder subjectBuilder = new StringBuilder(); for (int i = 0; i < group.size(); i++) { if (i > 0) subjectBuilder.append(", "); subjectBuilder.append(group.get(i).getSubject()); } groupedList.add(new TeacherClass( template.getClassId(), template.getClassName(), template.getSection(), subjectBuilder.toString() )); } return groupedList; }
内容的提问来源于stack exchange,提问作者Shikhar

