Java Lambda:迭代2个dim-array保持当前索引 [英] Java Lambda: Iterate over 2 dim-array keeping the current index

查看:124
本文介绍了Java Lambda:迭代2个dim-array保持当前索引的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我是Java 8的Lambda表达式的新手,我想制定以下内容:
我有一个二维数组,我想在我的应用程序代码中迭代几次,然后对这些项进行处理数组。在我执行以下操作之前:

I'm new to Java 8's Lambda Expressions and I want to formulate the following: I have a 2-dimensional array which I want to iterate over several times in my application code and do stuff with the items in the array. Before i'd do the following:

    public static abstract class BlaBlaIterator {

            private final BlaBla[][] blabla;

            public BlaBlaIterator(final BlaBla[][] blabla) {
                this.blabla = blabla;
            }

            public void iterate() {
                final int size = blabla.length;
                for (int x = 0; x < size; x++) {
                    for (int y = 0; y < size; y++) {
                        final BlaBla bla = blabla[x][y];
                        iterateAction(x, y, bla, bla == null);
                    }
                }
            }

            public abstract void iterateAction(int x, int y, BlaBla bla, boolean isNull);
        }

然后

    BlaBla[][] blabla = ...

    new BlaBlaIterator(blabla) {

        @Override
        public void iterateAction(final int x, final int y, final BlaBla bla, final boolean isNull) {
            //...
        }
    }.iterate();

至关重要:我需要访问当前的x / y,我需要计算像isNull。

Crucial thing: I need access to the current x/y and I need to get calculated things like the isNull.

我现在要做的是将其转换为lambda。我想写这样的东西:

What I want to do now is to convert this to lambda. I want to write something like this:

    BlaBla[] blabla = ...
    blabla.stream().forEach((x, y, blabla, isNull) -> ... );

要从二维数组中获取流,我可以做到

To get a stream from the 2-dimensional Array I can do

    Arrays.stream(field).flatMap(x -> Arrays.stream(x))

然后我松开了x / y信息并且无法传递像isNull这样的计算内容。我怎么能这样做?

But then I loose the x/y info and cannot pass calculated stuff like isNull. How can i do this?

推荐答案

老实说,我会保留传统的嵌套循环,IMO这是一个更清洁的方法。 Streams不是所有旧Java代码的替代品。不过,我发布了一些可能的方法。

To be honest I would keep the traditionnal nested loop, IMO this is a much cleaner approach. Streams are not a substition for all the "old" Java code. Nevertheless, I posted some possible approaches.

这是第一种可能的方法(面向对象) 。创建一个类 ArrayElement 来保存索引:

Here's a first possible approach (Object-oriented). Create a class ArrayElement to hold the indices:

class ArrayElement<V> {
    public final int row;
    public final int col;
    public final V elem;
    ...
}

然后你需要创建一个方法从单个数组(我们将为 flatMap 调用的那个)创建元素Stream,以及 iterateAction 打印出当前实例

Then you'll need to create a method that creates a Stream of elements from a single array (the one that we will call for flatMap), and iterateAction just print out the current instance

private static <T> Stream<ArrayElement<T>> createStream(int row, T[] arr) {
    OfInt columns = IntStream.range(0, arr.length).iterator();
    return Arrays.stream(arr).map(elem -> new ArrayElement<>(row, columns.nextInt(), elem));
} 

private static <V> void iterateAction(ArrayElement<V> elem) {
    System.out.println(elem);
}

最后主要看起来像这样:

Finally the main looks like this:

String[][] arr = {{"One", "Two"}, {"Three", "Four"}};
OfInt rows = IntStream.range(0, arr.length).iterator();
Arrays.stream(arr)
      .flatMap(subArr -> createStream(rows.nextInt(), subArr))
      .forEach(Main::iterateAction);

和输出:

ArrayElement [row=0, col=0, elem=One]
ArrayElement [row=0, col=1, elem=Two]
ArrayElement [row=1, col=0, elem=Three]
ArrayElement [row=1, col=1, elem=Four]

此解决方案的缺点是它为数组中的每个Object创建一个新Object。

This solution has the disadvantage that it creates a new Object for each Object in the array.

第二种方法更直接,它是相同的想法,但你不创建一个数组中每个elem的新ArrayElement实例。再一次,这可以在一个班轮上完成,但是lamdba会变得丑陋,所以我将这些方法分开(比如第一种方法):

The second approach is more direct, it's the same idea but you don't create a new ArrayElement instance for each elem in the array. Again this could be done in a one liner but the lamdba would become ugly so I splitted those up in methods (like in the first approach):

public class Main {    
    public static void main(String[] args) {
        String[][] arr = { {"One", "Two"}, {null, "Four"}};
        OfInt rows = IntStream.range(0, arr.length).iterator();
        Arrays.stream(arr).forEach(subArr -> iterate(subArr, rows.nextInt()));
    }
    static <T> void iterate(T[] arr, int row) {
        OfInt columns = IntStream.range(0, arr.length).iterator();
        Arrays.stream(arr).forEach(elem -> iterateAction(row, columns.nextInt(), elem, elem == null));
    }
    static <T> void iterateAction(int x, int y, T elem, boolean isNull) {
        System.out.println(x+", "+y+", "+elem+", "+isNull);
    }    
}

并输出:

0, 0, One, false
0, 1, Two, false
1, 0, null, true
1, 1, Four, false



第三种方式



使用两个 AtomicInteger实例

String[][] arr = {{"One", "Two"}, {null, "Four"}};
AtomicInteger rows = new AtomicInteger();
Arrays.stream(arr).forEach(subArr -> {
    int row = rows.getAndIncrement();
    AtomicInteger colums = new AtomicInteger();
    Arrays.stream(subArr).forEach(e -> iterateAction(row, colums.getAndIncrement(), e, e == null));
});

产生与上面相同的输出。

which produces the same output as above.

使用Streams是可行的,但我更喜欢你的用例中的嵌套循环,因为你需要x和y值。

It's duable using Streams but I really prefer the nested loop in your use-case since you need both the x and y values.

这篇关于Java Lambda:迭代2个dim-array保持当前索引的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆