代码之家  ›  专栏  ›  技术社区  ›  OldCurmudgeon

使用排序规则合并两个流

  •  2
  • OldCurmudgeon  · 技术社区  · 9 年前

    我需要以一种高效灵活的方式做一些矩阵工作,并希望我可以使用流和lambda来练习我的Java8,甚至可以从中获得自由的并行性。

    考虑一下简单的机制:

    static final List<String> a = Arrays.asList("A", "A", "A");
    static final List<String> b = Arrays.asList("B", "B", "B");
    
    public void withoutStreams() {
        // The boring old way.
        List<String> c = new ArrayList<>();
        for (Iterator<String> ai = a.iterator(), bi = b.iterator(); ai.hasNext() && bi.hasNext();) {
            c.add(ai.next() + bi.next());
        }
        System.out.println(c);
    }
    

    工作正常,但我想使用Streams。

    private void withStreams() {
        List<String> c = new ArrayList<>();
        combine(a.stream(), b.stream(), c, (String x, String y) -> x + y);
    }
    
    private void combine(Stream<String> a, Stream<String> b, List<String> c, BinaryOperator<String> op) {
        // What can I do here to make it happen?
    }
    

    我完全希望我们能填补空缺 c 使用 Consumer 除了使用(row,col)之外,还提出了一些引用矩阵中特定单元格的方法,并记住这些单元格是不可变的。

    2 回复  |  直到 9 年前
        1
  •  3
  •   Community Egal    7 年前

    您可以使用 IntStream 类来模拟索引,然后 .mapToObj 将对应于索引对象的 a b :

    List<String> list = IntStream.range(0, Math.max(a.size(), b.size()))
                                 .mapToObj(i -> a.get(i) + b.get(i))
                                 .collect(Collectors.toList());
    

    应用于您的方法,这将如下所示:

    private void combine(List<String> a, List<String> b, List<String> c, BinaryOperator<String> op) {
        c = IntStream.range(0, Math.max(a.size(), b.size()))
                     .mapToObj(i -> op.apply(a.get(i), b.get(i)))
                     .collect(Collectors.toList());
    }
    

    但是,如果您不想更改方法的签名, here is a solution which works for all possible combinations of infinite and finite streams :

    private void combine(Stream<String> a, Stream<String> b, List<String> c, BinaryOperator<String> op) {
        Iterator<String> i1 = a.iterator();
        Iterator<String> i2 = b.iterator();
        Iterable<String> i = () -> new Iterator<String>() {
            public boolean hasNext() {
                return i1.hasNext() && i2.hasNext();
            }
            public String next() {
                return op.apply(i1.next(), i2.next());
            }
        };
        c = StreamSupport.stream(i.spliterator(), false).collect(Collectors.toList());
    }
    
        2
  •  0
  •   卢声远 Shengyuan Lu    9 年前

    函数式编程风格,使用递归(无循环):

    static Stream<String> combine(List<String> a, List<String> b) {
        if(a.isEmpty() ||  b.isEmpty()) {
            return Stream.empty();
        }
    
        return Stream.concat(
                Stream.of(a.get(0) + b.get(0)),
                combine(a.stream().skip(1).collect(Collectors.toList()), 
                        b.stream().skip(1).collect(Collectors.toList()))
                );
    }
    

    加:我投票支持科科的答案,我的答案是为了好玩。