'Prepare new list based on conditions from two object lists using stream
I am working in spring boot application, working with lists.
I have these classes :
public class MyModel {
private String pptId;
private String pptTitle;
private String modelNumber;
}
public class FullData {
private String pptTitle;
private String modelNumber;
private String pptDetails;
private String price;
...............
..............
}
List sourceModelList = This is full list
MyModel(1,'ppt1','a1')
MyModel(1,'ppt1','a2')
MyModel(2,'ppt2','a1')
MyModel(2,'ppt2','a3')
MyModel(2,'ppt2','a4')
MyModel(3,'ppt3','a1')
MyModel(3,'ppt3','a3')
MyModel(3,'ppt3','a5')
I have filtered FullData list but that is filtered from some processing
List filteredFullDataList = it is unique list
FullData(null,'a1','pptDetails1','300')
FullData(null,,'a2','pptDetails21','70')
FullData(null,,'a4','pptDetails41','10')
FullData(null,'a5','pptDetails13','45')
Now I need to set the title and prepare list as in the order it present in sourceArticleList, only I have to remove non-existing modelNumber which is not present in filteredFullDataList as a3. But I need repeated models as they are presented in another ppt.
We need final list of FullData as :
FullData('ppt1','a1','pptDetails1','300')
FullData('ppt1',,'a2','pptDetails21','70')
FullData('ppt2','a1','pptDetails1','300')
FullData('ppt2','a4','pptDetails41','10')
FullData('ppt3','a1','pptDetails1','300')
FullData('ppt5','a5','pptDetails13','45')
I have tried streams and processed by seeting slide then preparing the FullData object and it's list, but it not working properly.
I need this below code into streams
List<FullData> finalFullData = new ArrayList();
for (MyModel myModel : sourceModelList) {
for (FullData fullData : filteredFullDataList) {
if (myModel.getModelNumber().equals(fullData.getModelNumber())) {
fullData.setPptTitle(myModel.setPptTitle());
finalFullData.add(fullData);
}
}
}
Solution 1:[1]
This task doesn't fit well into functional programming because it requires mutation of the stream elements and entails side effects. That means you will be using so-called impure functions.
I suggest you take a look at this link Difference between pure and impure function?
Instead of writing a solution that is fully functional in style by doesn't meet the good practices, I'll show the implementation that is more performant than the initial version with nested for-loops and also is partially functional in style.
Firstly, consider creating a map with a ModelNumber number as a key from one of the lists. It'll reduce the time complexity to linear time.
Then we still have to iterate over one of those lists. In this case, the imperative approach is necessary because it allows avoiding the use of impure lamdas.
public static void main(String[] args) {
List<MyModel> sourceModelList = getSourceModelList();
List<FullData> filteredFullDataList = getFilteredFullDataList();
Map<String, List<FullData>> modelNumberToFullData = getFullDataMap(filteredFullDataList);
Set<String> seen = new HashSet<>(); // stores modelNumbers that are already processed
List<FullData> finalFullData = new ArrayList();
for (MyModel myModel : sourceModelList) {
String modelNumber = myModel.getModelNumber();
if (seen.contains(modelNumber) || !modelNumberToFullData.containsKey(modelNumberToFullData))
continue;
for (FullData data: modelNumberToFullData.get(modelNumber)) {
data.setPptTitle(myModel.getPptTitle());
finalFullData.add(data);
}
seen.add(modelNumber);
}
}
public static Map<String, List<FullData>> getFullDataMap(List<FullData> fullDataList) {
return fullDataList.stream()
.collect(Collectors.groupingBy(FullData::getModelNumber));
}
I hope it'll be helpful. If you have any questions fill free to ask.
Solution 2:[2]
If you need to rewrite your last nested for loop using stream, you can do:
List<FullData> finalFullData = sourceModelList.stream()
.flatMap(myModel -> filteredFullDataList.stream()
.filter(fullData -> myModel.getModelNumber().equals(fullData.getModelNumber()))
.peek(fullData -> fullData.setPptTitle(myModel.getPptTitle())))
.toList();
Then:
finalFullData.forEach(System.out::println);
Output:
FullData[ppt3,a1,pptDetails1,300]
FullData[ppt1,a2,pptDetails21,70]
FullData[ppt3,a1,pptDetails1,300]
FullData[ppt2,a4,pptDetails41,10]
FullData[ppt3,a1,pptDetails1,300]
FullData[ppt3,a5,pptDetails13,45]
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 | |
| Solution 2 | Oboe |
