代码之家  ›  专栏  ›  技术社区  ›  Pablo Matias Gomez

在搜索重复项时,如何删除流中的第一个外观?

  •  2
  • Pablo Matias Gomez  · 技术社区  · 9 年前

    我有一个对象流,这些对象根据它们拥有的id定义equals和hashcode。所以我知道使用 stream.distinct() 我将得到一个没有任何副本的流,但它将保留第一个外观,而不是最后一个。

    对于有序流,不同元素的选择是稳定的 *(对于重复的元素,在遭遇中首先出现的元素 *保留顺序。)

    例如,如果我有这个项目列表 1,2,3,1,4,5 .

    如果我应用 distinct() 1,2,3,4,5 2,3,1,4,5 .我如何实现这一点?

    3 回复  |  直到 9 年前
        1
  •  8
  •   Oleg Estekhin    9 年前

    A定制 toMap 具有访问顺序的收集器 LinkedHashMap

    Stream.of( 1, 2, 3, 1, 4, 5 )
            .collect( Collectors.toMap(
                    key -> key,
                    value -> value,
                    ( oldValue, newValue ) -> newValue,
                    () -> new LinkedHashMap<>( 16, 0.75f, true )
            ) )
            .values()
            .stream()
            .forEach( System.out::println );
    

    保留项目最后外观的任务意味着您无论如何都必须在生成新流的第一个元素之前完全使用原始流,因此收集和创建新流并没有那么糟糕。正如注释中所建议的那样,反转、应用distinct并再次反转将完全消耗原始流和“distinct”流,因此使用专用收集器应该更好。

        2
  •  3
  •   fps    9 年前

    Oleg's answer 是绝对正确的,我在这里发布了做同样事情的其他方法,基于他使用 按顺序访问 LinkedHashMap

    Map<Integer, Integer> map = new LinkedHashMap<>(16, 0.75f, true); // access order
    Arrays.asList(1, 2, 3, 1, 4, 5)
        .forEach(e -> map.put(e, e)); // just put
    List<Integer> list1 = new ArrayList<>(map.values()); // discard the map
    
    System.out.println(list1); // [2, 3, 1, 4, 5]
    

    对于流,使用自定义收集器:

    List<Integer> list2 = Stream.of(1, 2, 3, 1, 4, 5)
        .collect(Collector.of(
            () -> new LinkedHashMap<Integer, Integer>(16, 0.75f, true),
            (m, e) -> m.put(e, e),
            (m1, m2) -> { m1.putAll(m2); return m1; },
            m -> new ArrayList<>(m.values())));
    
    System.out.println(list2); // [2, 3, 1, 4, 5]
    

    注:正如霍尔格在评论中指出的那样,使用 Map.values() 而不是 Map.keySet() 创建结果列表。这是因为当 m.put(e, e) 如果地图中已存在具有相同键的条目,则使用新值替换旧值,但键保持不变,即旧值。

        3
  •  1
  •   Vladimir Dimovski    5 年前

    public void removeDuplicates(){ 
         Collections.reverse(duplicatesList);
         duplicatesList = duplicatesList.stream().distinct().collect(Collectors.toList());
         Collections.reverse(duplicatesList);
         }
    
    推荐文章