LoginSignup
3
2

More than 5 years have passed since last update.

インデックスを参照するループをJava8のStreamAPIで書きたい

Last updated at Posted at 2017-08-06

みんな大好きStreamAPIですが、
拡張for文で書くようなループはキレイにかけますが、
ループ内部でインデックスを参照したいようなループはいまいちどうしたらいいのかわかりません。
(ぐぐっても独自クラス作っちゃうような方法がでてきたり:persevere:)

ということでちょっと頭をひねってみました。


「ループ内部でインデックスを参照したいようなループ」としては以下のようなケースを想定します。

  • 2つ以上のリストをまとめて回したい
  • 1つのリスト中の隣接する要素(iに対してi-1とかi+1とか)も参照したい

(iが参照できて、かつ好きな処理を書けるので、
「リストの最初/最後のときに処理を変えたい」とかのケースでも使えますが、
あんまりキレイじゃないかな、と思います。)

以下がコード例です。

    public static void main(String[] args) {
        // 乱数で作った適当なリスト
        List<Integer> listA = new ArrayList<>(Arrays.asList(12, 23, 66, 45, 10, 48, 21, 25, 68, 65));
        List<Integer> listB = new ArrayList<>(Arrays.asList(98, 96, 4, 33, 30, 38, 39, 25, 32, 64));

        // ケース1:2つのリストをまとめて扱いたい場合
        List<Boolean> isWinnerA = IntStream.range(0, Math.min(listA.size(), listB.size()))
                .mapToObj(i -> listA.get(i) > listB.get(i))
                .collect(Collectors.toList());
        System.out.println("isWinnerAList: " + isWinnerAList);
        // -> isWinnerA: [false, false, true, true, false, true, false, false, true, true]

        // ケース2:リストの中の前後をまとめて扱いたい場合
        List<Double> movingAverage = IntStream.range(0, listA.size() - 1)
                .mapToObj(i -> (listA.get(i) + listA.get(i + 1)) / 2d)
                .collect(Collectors.toList());
        System.out.println("movingAverage: " + movingAverage);
        // -> movingAverage: [17.5, 44.5, 55.5, 27.5, 29.0, 34.5, 23.0, 46.5, 66.5]
    }

構成としては、

  • for(int i; i < list.size(); i++)の部分
    • IntStreamのファクトリメソッドで作ります
    • 例のような単純な増加ならrange(startInclusive, endExclusive)でいけます
    • インクリメントの大きさを変えたいならiterate(seed, f).limit(maxSize)とか(参照する方でi*2してもいいですが)
    • generate(s)を使えば大抵のことはできるはず
  • ループ内の処理
    • mapToObj(/* 変換処理 */).collect(/* 集約処理 */);
    • 集約しなくて良いならforEach()で済みますが。

pro:標準で用意されてるものだけで書ける
con:Stream慣れてる人じゃないと困惑するかも

普通にfor文で書いた方がいいって言われますかね・・・?
まぁ、例に使ってる程度のものなら普通にfor文書いてもいいかもですが、filter()とか、集約処理とか、Streamの機能が活きるケースだと使えるかな?と思います。

3
2
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
2