如何删除List <T> JAVA 8中的重复项

Mbd*_*ded 6 java collections java-8

实际上,我知道减少重复distinct()或分配的List方法Set,但我有一些不同的问题.如何解决JAVA 8中使用流的问题以下的智能方式或可能StreamEx

假设我们在List中有一个对象

A, A, A, B, B, A, A, A, C, C, C, A, A, B, B, A

现在我需要

A, B, A, C, A, B, A

所以复制被删除了,但只有当下一个出现时,但如果旁边是不同的对象则应该保留.我尝试了一些解决方案但是丑陋,而且不易阅读.

And*_*eas 11

选项1:过滤

可以写一个有状态的过滤器,但你永远不应该这样做,因为它违反了以下合同filter(Predicate<? super T> predicate):

predicate-一个非干扰,无国籍谓词应用到每个元素,以确定是否它应包含

public class NoRepeatFilter<T> implements Predicate<T> {
    private T prevValue;
    @Override
    public boolean test(T value) {
        if (value.equals(this.prevValue))
            return false;
        this.prevValue = value;
        return true;
    }
}
Run Code Online (Sandbox Code Playgroud)

测试

List<String> result = Stream
        .of("A", "A", "A", "B", "B", "A", "A", "A", "C", "C", "C", "A", "A", "B", "B", "A")
//      .parallel()
        .filter(new NoRepeatFilter<>())
        .collect(Collectors.toList());
System.out.println(result);
Run Code Online (Sandbox Code Playgroud)

产量

[A, B, A, C, A, B, A]

它必须是无状态的原因是,如果流是并行的,它将失败,例如,使用未.parallel()注释的方式再次运行测试:

[A, A, B, B, A, C, C, C, A, B, B, A]


选项2:收集者

有效的解决方案是Collector使用of(...)以下方法创建自己的:

public class NoRepeatCollector {
    public static <E> Collector<E, ?, List<E>> get() {
        return Collector.of(ArrayList::new,
                            NoRepeatCollector::addNoRepeat,
                            NoRepeatCollector::combineNoRepeat);
    }
    private static <E> void addNoRepeat(List<E> list, E value) {
        if (list.isEmpty() || ! list.get(list.size() - 1).equals(value))
            list.add(value);
    }
    private static <E> List<E> combineNoRepeat(List<E> left, List<E> right) {
        if (left.isEmpty())
            return right;
        if (! right.isEmpty())
            left.addAll(left.get(left.size() - 1).equals(right.get(0))
                        ? right.subList(1, right.size()) : right);
        return left;
    }
}
Run Code Online (Sandbox Code Playgroud)

测试

List<String> result = Stream
        .of("A", "A", "A", "B", "B", "A", "A", "A", "C", "C", "C", "A", "A", "B", "B", "A")
//      .parallel()
        .collect(NoRepeatCollector.get());
System.out.println(result);
Run Code Online (Sandbox Code Playgroud)

输出(有和没有.parallel())

[A, B, A, C, A, B, A]


选项3:循环

如果您的输入是List(或其他Iterable),则可以使用简单循环删除重复值:

public static <E> void removeRepeats(Iterable<E> iterable) {
    E prevValue = null;
    for (Iterator<E> iter = iterable.iterator(); iter.hasNext(); ) {
        E value = iter.next();
        if (value.equals(prevValue))
            iter.remove();
        else
            prevValue = value;
    }
}
Run Code Online (Sandbox Code Playgroud)

测试

List<String> list = new ArrayList<>(Arrays.asList(
        "A", "A", "A", "B", "B", "A", "A", "A", "C", "C", "C", "A", "A", "B", "B", "A"));
removeRepeats(list);
System.out.println(list);
Run Code Online (Sandbox Code Playgroud)

产量

[A, B, A, C, A, B, A]

  • 有状态的谓词是......有状态的.如果流是顺序的,它可以工作,但我认为不应该鼓励这种解决方案.如果list/iterable在第一个位置包含null元素,则循环解决方案失败,否则它很好.最后,由于基于收集器的解决方案,我投票赞成,这应该是2018年java开发人员的常识. (3认同)