'Java 8 - Best way to separate a list into 3 different lists
Input:
- I have a List abcLines which has all types of lines of type A or B or C.
- I also have a readymade List of type A (aLines).
I want to separate the big list (abcLines) into 3 different lists (aLines, bLines and cLines).
class ABCLine {
int id;
Object tlId; // value of this field is false (if the line type is A or C) or the value of this field is a List (if the type is B)
}
List<ABCLine> bLines = new ArrayList<ABCLine>();
List<ABCLine> cLines = new ArrayList<ABCLine>();
abcLines.forEach(abcLine -> {
if (abcLine.tlId instanceof List) {
bLines.add(abcLine);
abcLines.remove(abcLine);
} else {
aLines.forEach(aLine -> {
if (aLine.id.equals(abcLine.id)) {
abcLines.remove(abcLine);
}
});
}
});
cLines = abcLines;
How can I write this code using Java 8 streams in a better way?
Solution 1:[1]
Here's a solution that uses Collectors.partitioningBy to separate the lines.
List<ABCLine> aLines = new ArrayList<>(); //Ready made aline list
List<ABCLine> abcLines = new ArrayList(); // list that contains the A B and C lines.
//1. We first separate the b lines from the a and c lines by checking whether the field `tlId` of an instance is a `List` or not. We use `Collectors.partitioningBy` to partition the instances based on this condition. The end result is a map holding two lists that can be retrieved with the keys `true` and `false`.
Map<Boolean, List<ABCLine>> partitionedLines = abcLines.stream().collect(Collectors.partitioningBy(abcLine -> abcLine.tlId instanceof List));
//2. Retrieve the B lines from the map.
List<ABCLine> separatedBLines = partitionedLines.get(true);
//3. Retrieve the A and C lines from the map.
List<ABCLine> aAndCLines = partitionedLines.get(false);
//4. Make a Set containing all the `id` field values from the ready made aline list that you mentioned. This Set will be used to partition the a lines from the c lines.
Set<Integer> aLineIds = aLines.stream().map(aLine -> aLine.id).collect(Collectors.toSet());
//5. We use `Collectors.partitioningBy` again to partition/separate the A lines from the C lines using `aLineIds.contains(line.id)` as the condition. Because the type of the aList id collection is a set we can determine very fast whether the `id` of `line` equals any of the ids in the set.
Map<Boolean, List<ABCLine>> aAndCMap = aAndCLines.stream().collect(Collectors.partitioningBy(line -> aLineIds.contains(line.id)));
//6. Now you only have to retrieve the A and C lines from the map and you're done.
List<ABCLine> separatedALines = aAndCMap.get(true);
List<ABCLine> separatedCLines = aAndCMap.get(false);
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 |
