从流中收集对

2022-09-03 06:57:57

我有一个这样的对象流:

"0", "1", "2", "3", "4", "5",

如何将其转换为对流:

{ new Pair("0", "1"), new Pair("2", "3"), new Pair("4", "5")}.

流大小未知。我正在从可能很大的文件中读取数据。我只有迭代器到集合,我使用拆分器将此迭代器转换为流。我知道这是使用StreamEx处理相邻对的答案:从流中收集连续的对可以在java或StreamEx中完成吗?谢谢


答案 1

这不是一个自然的契合,但你可以做

List input = ...
List<Pair> pairs = IntStream.range(0, input.size() / 2)
                            .map(i -> i * 2)
                            .mapToObj(i -> new Pair(input.get(i), input.get(i + 1)))
                            .collect(Collectors.toList());

要在流中创建对,您需要一个有状态的 lambda,这通常应该避免,但可以做到。注意:这仅在流是单线程时才有效。即不平行。

Stream<?> stream = 
assert !stream.isParallel();
Object[] last = { null };
List<Pair> pairs = stream.map(a -> {
        if (last[0] == null) {
            last[0] = a;
            return null;
        } else {
            Object t = last[0];
            last[0] = null;
            return new Pair(t, a);
        }
     }).filter(p -> p != null)
       .collect(Collectors.toList());
assert last[0] == null; // to check for an even number input.

答案 2

假设有一个 with 、和 getters 和一个构造函数:Pairleftright

 static class Paired<T> extends AbstractSpliterator<Pair<T>> {

    private List<T> list = new ArrayList<>(2);

    private final Iterator<T> iter;

    public Paired(Iterator<T> iter) {
        super(Long.MAX_VALUE, 0);
        this.iter = iter;
    }

    @Override
    public boolean tryAdvance(Consumer<? super Pair<T>> consumer) {
        getBothIfPossible(iter);
        if (list.size() == 2) {
            consumer.accept(new Pair<>(list.remove(0), list.remove(0)));
            return true;
        }
        return false;
    }

    private void getBothIfPossible(Iterator<T> iter) {
        while (iter.hasNext() && list.size() < 2) {
            list.add(iter.next());
        }
    }

}

用法为:

 Iterator<Integer> iterator = List.of(1, 2, 3, 4, 5).iterator();
 Paired<Integer> p = new Paired<>(iterator);
 StreamSupport.stream(p, false)
            .forEach(pair -> System.out.println(pair.getLeft() + "  " + pair.getRight()));

推荐