如何将多个List<DTO1>的数据合并到单个List<DTO2>中?
Hey there! Let's work through this problem together. It looks like you need to combine three List<DTO1> collections (ListA, ListB, ListC) into a single List<DTO2>, where each DTO2 entry captures the count values from each source list tied to the same id and userLogin pair. Here's a straightforward, effective way to do this:
Step 1: Confirm DTO Definitions
First, let's align on the DTO structures you mentioned. I'll assume they look like this (adjust getters/setters or constructors as needed for your codebase):
// DTO1: Contains the source data public class DTO1 { private Long id; private String userLogin; private Integer count; // Getters, Setters, and Constructor(s) public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getUserLogin() { return userLogin; } public void setUserLogin(String userLogin) { this.userLogin = userLogin; } public Integer getCount() { return count; } public void setCount(Integer count) { this.count = count; } } // DTO2: The target structure with count fields for each source list public class DTO2 { private Long id; private String userLogin; private Integer countListA; private Integer countListB; private Integer countListC; // Getters, Setters, and Constructor(s) public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getUserLogin() { return userLogin; } public void setUserLogin(String userLogin) { this.userLogin = userLogin; } public Integer getCountListA() { return countListA; } public void setCountListA(Integer countListA) { this.countListA = countListA; } public Integer getCountListB() { return countListB; } public void setCountListB(Integer countListB) { this.countListB = countListB; } public Integer getCountListC() { return countListC; } public void setCountListC(Integer countListC) { this.countListC = countListC; } }
Step 2: Merge Logic Using a Map
The key here is to group entries by their unique id + userLogin pair, then populate the corresponding count fields in DTO2. We'll use a Map to track these pairs and build our DTO2 objects incrementally:
import java.util.*; import java.util.function.BiConsumer; public class DtoMerger { public List<DTO2> mergeDtoLists(List<DTO1> listA, List<DTO1> listB, List<DTO1> listC) { // Map to hold DTO2 entries, keyed by (id, userLogin) pair Map<Map.Entry<Long, String>, DTO2> dto2Map = new HashMap<>(); // Populate the map with each source list, setting the correct count field populateDtoMap(listA, dto2Map, DTO2::setCountListA); populateDtoMap(listB, dto2Map, DTO2::setCountListB); populateDtoMap(listC, dto2Map, DTO2::setCountListC); // Convert the map values to our final List<DTO2> return new ArrayList<>(dto2Map.values()); } // Helper method to handle populating the map from a single source list private void populateDtoMap(List<DTO1> sourceList, Map<Map.Entry<Long, String>, DTO2> dto2Map, BiConsumer<DTO2, Integer> countSetter) { for (DTO1 dto1 : sourceList) { // Create a unique key from id and userLogin Map.Entry<Long, String> key = new AbstractMap.SimpleEntry<>(dto1.getId(), dto1.getUserLogin()); // Create a new DTO2 if this key doesn't exist yet, initialize base fields dto2Map.computeIfAbsent(key, k -> { DTO2 dto2 = new DTO2(); dto2.setId(k.getKey()); dto2.setUserLogin(k.getValue()); // Initialize counts to null (or 0 if you prefer default values) dto2.setCountListA(null); dto2.setCountListB(null); dto2.setCountListC(null); return dto2; }); // Set the count value for the current source list countSetter.accept(dto2Map.get(key), dto1.getCount()); } } }
How This Works
- Unique Key: We use
Map.Entry<Long, String>as the map key to represent the unique combination ofidanduserLogin. This ensures we group all entries that belong to the same user/id pair. - Lazy Initialization:
computeIfAbsentcreates a new DTO2 only when we first encounter a key, setting up the baseidanduserLoginvalues. - Count Population: The helper method uses a
BiConsumerto set the correct count field (countListA, countListB, or countListC) based on which source list we're processing. - Handling Missing Entries: If a user/id pair doesn't exist in one of the source lists, the corresponding count field will stay
null(you can change this to0in the initialization step if needed).
Optional: Stream-Based Approach
If you prefer using Java Streams for a more declarative style, here's an alternative implementation:
import java.util.*; import java.util.stream.Collectors; import java.util.stream.Stream; public class StreamDtoMerger { public List<DTO2> mergeWithStreams(List<DTO1> listA, List<DTO1> listB, List<DTO1> listC) { // Combine all source entries with a tag indicating which list they came from Stream<Map.Entry<DTO1, String>> taggedEntries = Stream.concat( listA.stream().map(dto -> new AbstractMap.SimpleEntry<>(dto, "A")), Stream.concat( listB.stream().map(dto -> new AbstractMap.SimpleEntry<>(dto, "B")), listC.stream().map(dto -> new AbstractMap.SimpleEntry<>(dto, "C")) ) ); // Group by id+userLogin, then build DTO2 from grouped entries return taggedEntries.collect(Collectors.groupingBy( entry -> new AbstractMap.SimpleEntry<>(entry.getKey().getId(), entry.getKey().getUserLogin()), Collectors.collectingAndThen(Collectors.toList(), entries -> { DTO2 dto2 = new DTO2(); DTO1 firstDto = entries.get(0).getKey(); dto2.setId(firstDto.getId()); dto2.setUserLogin(firstDto.getUserLogin()); // Populate counts based on the source tag entries.forEach(entry -> { switch (entry.getValue()) { case "A": dto2.setCountListA(entry.getKey().getCount()); break; case "B": dto2.setCountListB(entry.getKey().getCount()); break; case "C": dto2.setCountListC(entry.getKey().getCount()); break; } }); return dto2; }) )) .values() .stream() .collect(Collectors.toList()); } }
Notes
- Duplicate Entries: If a user/id pair appears multiple times in a single source list, both implementations will use the last encountered
countvalue. If you need to sum counts instead, modify the logic to add to the existing value instead of overwriting it. - Lombok: To reduce boilerplate code, consider using Lombok's
@Dataannotation on your DTO classes to auto-generate getters, setters, and constructors.
内容的提问来源于stack exchange,提问作者sina ardehali

