【问题标题】:Get map from two list having similar object ID从具有相似对象 ID 的两个列表中获取地图
【发布时间】:2020-09-10 07:58:49
【问题描述】:

我是 java 流 API 的新手。 我有 2 个列表,如果它们的内部对象 ID 都匹配,则希望将一些属性放入 MAP。 下面是实现。

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());
    }
}

【问题讨论】:

  • 某些操作不是针对流进行的。查看以下答案的复杂性。不值得将完全可读的代码转换为流管道。

标签: java dictionary java-8 java-stream


【解决方案1】:

创建一组lookupIds Set&lt;Long&gt; ids 可帮助您丢弃重复值并摆脱不必要的检查。

然后您可以使用examTypeId 值相应地过滤marksDetailList

filter(m -&gt; ids.contains(m.getExamTypeId()))

HashSet contains() 方法具有恒定的时间复杂度 O(1)。

试试这个:

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));

【讨论】:

    【解决方案2】:

    只要您正在寻找具有相同 ID 的这些,那么您使用哪个 ID 都没有关系。我建议您首先开始流式传输marksDetailList,因为您需要它的getMarks()。过滤方法搜索 ID 是否匹配。如果是这样,请将所需的键值收集到地图。

    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
    

    .map(..).anyMatch(..) 可以缩成一个:

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

    正如 cmets 中所述,为了简洁起见,我宁愿进行 for-each 迭代,因为您已经使用过。

    【讨论】:

      【解决方案3】:

      观察:

      首先,您的结果映射表明 ID 类型只能有一个匹配项(否则您将有重复的键,并且值需要是 List 或其他合并重复键的方式,而不是 @987654322 @. 所以当你找到第一个并将其插入地图时,跳出内部循环。

      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;
              }
          }
      }
      

      此外,如果您的两个类由可以访问id 的父类或共享接口相关联,并且基于id 将这两个类视为equal,那么您可以执行类似的操作到这个。

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

      当然,查找索引的负担仍然存在,但它现在已经在后台,您可以免除该责任。

      【讨论】:

        【解决方案4】:

        您可以使用HashMap 处理O(N) 的时间复杂度,首先将两个列表转换为Map&lt;Integer, LookupMstEntity&gt;Map&lt;Integer, MarksMstEntity&gt;,其中id 为键

        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
        

        然后流式传输examTypes 映射,然后如果MarksMstEntitymarks 映射中存在相同的ID,则将其收集到映射中

        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));
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2015-03-08
          • 2015-10-13
          • 1970-01-01
          • 1970-01-01
          • 2023-03-18
          • 2015-03-14
          相关资源
          最近更新 更多