【问题标题】:Java Streams for looping twice over same listJava Streams 在同一个列表上循环两次
【发布时间】:2018-12-10 08:59:45
【问题描述】:

我是 java 8 的新手,由于某种原因我在理解流时遇到了问题。假设我们有一个对象列表 List,其中 MyObject 有 2 个字段:Long Id、Date insertTime,并且我想删除具有相同 ID 和更早时间的元素。

有 2 个 for 循环是这样的:

for(MyObject object : myObjects) {
   for(MyObject tmpObject : myObjects) {
      if(object.getId() == tmpObject.getId()) {
         if(object.getInsertDate().after(tmpObject.getInsertDate())) 
           myObjects.remove(tmpObject);
         else 
           myObjects.remove(object);
      }
   }
}

使用流时这会是什么样子?

@Michael 我的错。比我需要另一个列表或数组来存储响应数据。

假设我有

  1. 1234 : 25/5/1991
  2. 1235 : 25/5/1995
  3. 1234 : 25/5/1999

所以我需要结果

  1. 1235 : 25/5/1995
  2. 1234 : 25/5/1999

谢谢大家。

【问题讨论】:

  • “有 2 个 for 循环是这样的”恐怕不是,因为在迭代列表时无法从列表中删除。
  • 附带说明,您应该始终在您的陈述中使用{},因为从长远来看,这会让您的生活更轻松。
  • @AxelH 我想equals 方法是错误的地方。 equals 方法应该为相同的 id(以及可选的相同日期)返回 true
  • 是的@Glains,我没有读到日期应该更早......所以它不正确。
  • 您可以执行以下操作: List> collect = list.stream().collect(groupingBy(MyObj::getId, maxBy(Comparator.comparing(MyObj::getDate) ))).values().stream().collect(toList());

标签: java loops java-8 nested java-stream


【解决方案1】:

按 id 分组,然后为每个 id 选择插入日期最长的那个。您可以将 Sample 替换为 MyObject。

    Map<Long, List<Sample>> map = list.stream().collect(Collectors.groupingBy(Sample::getId));
    map.values().stream()
            .map(samples -> Collections.max(
                    samples, Comparator.comparing(Sample::getInsertDate)))
            .collect(Collectors.toList());

【讨论】:

  • 不是将每个组收集到一个List中,而是在第二步中选择最大元素,您可以让groupingBy操作首先收集最大元素,如@987654321 @.
【解决方案2】:

你可以这样做,

List<MyObject> latestObjects = myObjects.stream()
    .collect(Collectors.collectingAndThen(
        Collectors.groupingBy(MyObject::getId,
            Collectors.maxBy(Comparator.comparing(MyObject::getInsertTime))),
        map -> map.values().stream().map(op -> op.orElse(null)).collect(Collectors.toList())));

首先将对象按其 Id 值分组,然后将其减少以仅保留每个 Id 值的最新对象,最后将它们收集到 List

更新

这可以根据下面的评论进一步改进。这是它的增强版。

List<MyObject> latestObjects = myObjects.stream()
    .collect(Collectors.collectingAndThen(Collectors.toMap(MyObject::getId, 
        o -> o, BinaryOperator.maxBy(Comparator.comparing(MyObject::getInsertTime))), 
            map -> new ArrayList<>(map.values())));

【讨论】:

  • 当下游收集器是减少时(即所有这些你必须在之后处理Optional的情况),你可以使用toMap而不是groupingByList&lt;MyObject&gt; latestObjects = myObjects.stream() .collect(Collectors.collectingAndThen( Collectors.toMap(MyObject::getId, Function.identity(), BinaryOperator.maxBy(Comparator.comparing(MyObject::getInsertTime))), map -&gt; new ArrayList&lt;&gt;(map.values())));跨度>
  • 完全同意你的看法。感谢您提供宝贵的反馈!
猜你喜欢
  • 2011-11-18
  • 2016-04-07
  • 2012-05-29
  • 1970-01-01
  • 1970-01-01
  • 2013-11-13
  • 1970-01-01
  • 1970-01-01
  • 2011-03-09
相关资源
最近更新 更多