简体   繁体   中英

Get map from two list having similar object ID

I'm new to java stream API. I have 2 lists, and if both their internal object ID matches wants to put some attributes to MAP. Below is the implementation.

List<LookupMstEntity> examTypeDetails; //This list contains values init.
List<MarksMstEntity> marksDetailList;  //This list contains values init.

//FYI above entities have lombok setter, getter, equals & hashcode.

Map<Long, Integer> marksDetailMap = new HashMap<>();

//need below implementation to changed using java 8.
for (LookupMstEntity examType : examTypeDetails) {
    for (MarksMstEntity marks : marksDetailList) {
        if (examType.getLookupId() == marks.getExamTypeId())
            marksDetailMap.put(examType.getLookupId(), marks.getMarks());
    }
}

Creating a set of lookupIds Set<Long> ids helps you to throw away duplicate values and to get rid of unnecessary checks.

Then you can filter marksDetailList accordingly with examTypeId values:

filter(m -> ids.contains(m.getExamTypeId()))

HashSet contains() method has constant time complexity O(1).

Try this:

Set<Long> ids = examTypeDetails.stream().map(LookupMstEntity::getLookupId)
        .collect(Collectors.toCollection(HashSet::new));

Map<Long, Integer> marksDetailMap = marksDetailList.stream().filter(m -> ids.contains(m.getExamTypeId()))
        .collect(Collectors.toMap(MarksMstEntity::getExamTypeId, MarksMstEntity::getMarks));

As long as you are looking for these with equal ID, it doesn't matter which ID you use then. I suggest you to start streaming the marksDetailList first since you need its getMarks() . The filtering method searches if there is a match in IDs. If so, collect the required key-values to the map.

Map<Long, Integer> marksDetailMap = marksDetailList.stream() // List<MarksMstEntity>
    .filter(mark -> examTypeDetails.stream()                 // filtered those where ...
        .map(LookupMstEntity::getLookupId)                   // ... the lookupId
        .anyMatch(id -> id == mark.getExamTypeId()))         // ... is present in the list
    .collect(Collectors.toMap(                               // collected to Map ...
        MarksMstEntity::getExamTypeId,                       // ... with ID as a key
        MarksMstEntity::getMarks));                          // ... and marks as a value

The .map(..).anyMatch(..) can be shrink into one:

.anyMatch(exam -> exam.getLookupId() == mark.getExamTypeId())

As stated in the comments, I'd rather go for the for-each iteration as you have already used for sake of brevity.

An observation:

First, your resultant map indicates that there can only be one match for ID types (otherwise you would have duplicate keys and the value would need to be a List or some other way of merging duplicate keys, not an Integer . So when you find the first one and insert it in the map, break out of the inner loop.

for (LookupMstEntity examType : examTypeDetails) {  
    for (MarksMstEntity marks : marksDetailList) {
        if (examType.getLookupId() == marks.getExamTypeId()) {
                marksDetailMap.put(examType.getLookupId(),
                            marks.getMarks());
                // no need to keep on searching for this ID
                break;
        }
    }
}

Also if your two classes were related by a parent class or a shared interface that had access to to the id , and the two classes were considered equal based on that id , then you could do something similar to this.

for (LookupMstEntity examType : examTypeDetails) {
    int index = marksDetailList.indexOf(examType);
    if (index > 0) {
            marksDetailMap.put(examType.getLookupId(),
                    marksDetaiList.get(index).getMarks());
    }
}

Of course the burden of locating the index is still there but it is now under the hood and you are relieved of that responsibility.

You can do it with O(N) time complexity using HashMap , first convert two lists into Map<Integer, LookupMstEntity> and Map<Integer, MarksMstEntity> with id as key

Map<Integer, LookupMstEntity> examTypes = examTypeDetails.stream()
                                          .collect(Collectors.toMap(LookupMstEntity::getLookupId, 
                                                         Function.identity())  //make sure you don't have any duplicate LookupMstEntity objects with same id

Map<Integer, MarksMstEntity> marks = marksDetailList.stream()
                                          .collect(Collectors.toMap(MarksMstEntity::getExamTypeId, 
                                                         Function.identity())   // make sure there are no duplicates

And then stream the examTypes map and then collect into map if MarksMstEntity exists with same id in marks map

Map<Integer, Integer> result = examTypes.entrySet()
                                        .stream()
                                        .map(entry->new AbstractMap.SimpleEntry<Integer, MarksMstEntity>(entry.getKey(), marks.get(entry.getKey())))
                                        .filter(entry->entry.getValue()!=null)
                                        .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM