实际上,我知道如何减少重复的distinct(),或者将List分配给Set,但我有一个不同的问题。如何在JAVA 8中使用流或可能是StreamEx来解决以下问题?
假设我们在列表中有一个对象
A, A, A, B, B, A, A, A, C, C, C, A, A, B, B, A
现在我需要
A, B, A, C, A, B, A
因此,复制被移除,但只有在显示为next时才会删除,但是如果next是不同的对象,则应该保持不变。我尝试了一些解决方案,但软件很难看,而且无法读懂。
发布于 2018-03-10 20:11:18
选项1:过滤器
您可以编写有状态筛选器,但是不应该这样做,因为它违反了filter(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;
}
}测试
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);输出
[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;
}
}测试
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);输出(带和不带.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;
}
}测试
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);输出
[A, B, A, C, A, B, A]
发布于 2018-03-10 19:38:35
它很简单,不用流。就像这样:
public List<T> noConsecutiveDuplicates(final List<T> input) {
final List<T> output = new ArrayList<>();
for (final T element : input) {
if (!element.equals(lastElement(output))) {
output.add(element);
}
}
return output;
}
private T lastElement(final List<T> list) {
if (list.size() == 0) {
return null;
}
return list.get(list.size() - 1);
}发布于 2018-03-11 18:31:15
我会给StreamEx一次机会使用StreamEx::collapse
List<String> strings = Arrays.asList("A", "A", "A", "B", "B", "A", "A", "A", "C", "C", "C", "A", "A", "B", "B", "A");
List<String> collect = StreamEx.of(strings)
.collapse(Objects::equals)
.collect(Collectors.toList());使用vanilla并利用“边缘检测”的思想也是可能的。
List<String> collect = IntStream.range(0, strings.size())
.filter(i -> i == 0 || !Objects.equals(strings.get(i - 1), strings.get(i)))
.mapToObj(strings::get)
.collect(Collectors.toList());https://stackoverflow.com/questions/49213102
复制相似问题