52

IteratorPython で次のジェネレーター関数のように動作する Java で実装したいと思います。

def iterator(array):
   for x in array:
      if x!= None:
        for y in x:
          if y!= None:
            for z in y:
              if z!= None:
                yield z

Java 側の x は、多次元配列または何らかの形式のネストされたコレクションにすることができます。これがどのように機能するかはわかりません。アイデア?

4

9 に答える 9

51

同じニーズがあったので、そのための小さなクラスを書きました。ここではいくつかの例を示します。

Generator<Integer> simpleGenerator = new Generator<Integer>() {
    public void run() throws InterruptedException {
        yield(1);
        // Some logic here...
        yield(2);
    }
};
for (Integer element : simpleGenerator)
    System.out.println(element);
// Prints "1", then "2".

無限ジェネレーターも可能です。

Generator<Integer> infiniteGenerator = new Generator<Integer>() {
    public void run() throws InterruptedException {
        while (true)
            yield(1);
    }
};

このGeneratorクラスは内部で Thread と連携してアイテムを生成します。をオーバーライドfinalize()することで、対応するジェネレーターが使用されなくなった場合にスレッドが残らないようにします。

パフォーマンスは明らかに素晴らしいものではありませんが、あまりにも粗末でもありません. 2.67 GHz のデュアル コア i5 CPU を搭載した私のマシンでは、0.03 秒未満で 1000 個のアイテムを生成できます。

コードはGitHubにあります。そこでは、それを Maven/Gradle の依存関係として含める方法についての説明も見つかります。

于 2014-01-07T12:07:45.007 に答える
5

Javaにはyieldがないため、これらすべてを自分で行う必要があり、最終的に次のようなばかげたコードになります。

    for(Integer z : new Iterable<Integer>() {

        @Override
        public Iterator<Integer> iterator() {

            return new Iterator<Integer>() {

                final Integer[][][] d3 = 
                        { { { 1, 2, 3 }, { 4, 5, 6 }, { 7, 8, 9 } },
                        { { 10, 11, 12 }, { 13, 14, 15 }, { 16, 17, 18 } },
                        { { 19, 20, 21 }, { 22, 23, 24 }, { 25, 26, 27 } } };

                int x = 0; 
                int y = 0; 
                int z = 0;

                @Override
                public boolean hasNext() {
                    return !(x==3 && y == 3 && z == 3);
                }

                @Override
                public Integer next() {
                    Integer result = d3[z][y][x];
                    if (++x == 3) {
                        x = 0;
                        if (++y == 3) {
                            y = 0;
                            ++z;
                        }
                    }
                    return result;
                }

                @Override
                public void remove() {
                    throw new UnsupportedOperationException();
                }
            };
        }
    }) {
        System.out.println(z);
    }

しかし、サンプルに複数のシングルがある場合、yield結果はさらに悪化します。

于 2012-07-19T22:40:42.137 に答える
2

質問で説明した Python データ構造は、次の Java タイプを使用して記述できると仮定します。

List<List<List<T>>>;

そして、次のような操作でそれを使用したい:

for (T z : iterator(array)) {
  // do something with z
}

その場合、iterator()Java 8 ストリームを使用して Python をかなり簡単に実装できます。

public <T> Iterable<T> iterator(List<List<List<T>>> array) {
  return array.stream()
      .filter(Objects::nonNull) // -> emits stream of non-null `x`s
    .flatMap(x -> x.stream()).filter(Objects::nonNull) // -> emits […] `y`s
    .flatMap(y -> y.stream()).filter(Objects::nonNull) // -> emits […] `z`s
    .collect(Collectors.toList()); // get list of non-null `z`s to iterate on
}

もちろん、結果を収集して、さらにストリーミング処理するためにストリームを出力することはできません (人々はそれが良い考えだと言っています)。

public <T> Stream<T> streamContent(List<List<List<T>>> array) {
  return array.stream()
      .filter(Objects::nonNull) // -> emits stream of non-null `x`s
    .flatMap(x -> x.stream()).filter(Objects::nonNull) // -> emits […] `y`s
    .flatMap(y -> y.stream()).filter(Objects::nonNull); // -> emits […] `z`s
}

// ...

streamContent(array).forEach(z -> {
  // do something with z
});
于 2020-09-13T11:52:05.453 に答える
-2

いいえ、Java 自体には「ジェネレーター」や「イールド」はありませんが、オブザーバー パターンを使用することで同じ機能を利用できます。これは、RxJavaなどの最新の実装を使用すると強化されます。コードは Obserable にサブスクライブし、Observable から次の値を読み取ろうとするたびに、次の値を「生成」します。Observable は、Python や JavaScript のジェネレーターのように独自の状態を維持できます。読み取る新しい値がない場合、「next()」メソッドは、新しいデータが利用可能になるのを待ってブロックします。これの良い例はHEREにあります。

于 2015-12-11T21:39:07.163 に答える