質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.37%
Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

Q&A

解決済

2回答

8692閲覧

2つの配列の同インデックス要素を演算する for ループの Stream への書き直し方

JavaTea

総合スコア29

Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

0グッド

0クリップ

投稿2016/11/05 07:44

編集2016/11/05 10:56

###前提・実現したいこと
最近 Java を学び始め、Java8 では多くのループ構造を Stream API で実装可能であり、またこれからは可能な限りそうするべきとも伺いました。
私としても可能な限りの Stream の活用を心掛けたく思うのですが、2つの配列の同インデックス同士を演算していくような for ループの Stream での上手い書き方を思いつけずにおります。
下記のような for ループを上手く Stream 化する方法にお知恵をお貸しいただけましたら幸いです。
###該当のソースコード

Java

1public static void main(String[] args) { 2 3 // main の引数から配列のサイズを指定 4 int limit = Integer.parseInt(args[0]); 5 6 // 1 ずつインクリメントする int 配列を作成。 limit が 5 なら {1, 2, 3, 4, 5} 7 int[] arr1 = Stream.iterate(1, i -> i + 1).limit(limit).mapToInt(Integer::intValue).toArray(); 8 9 // 1 から 10 倍していく int 配列を作成。 limit が 5 なら {1, 10, 100, 1000, 10000} 10 int[] arr2 =Stream.iterate(1, i -> i * 10).limit(limit).mapToInt(Integer::intValue).toArray(); 11 12// 配列 arr1, arr2 は for ループ内の動きを模式的に表すためのサンプルとなります。 13//説明の足りませんでした点を補いますと、任意の値を内容に持つ2つの配列で 14//同インデックス同士を対応させていくようなループ処理を模索しております。 15 16 // arr1 の各要素に arr2 の対応インデックスを掛け合わせていく、このような for ループを Stream 化したい 17 for(int i =0; i < arr1.length; i++){ 18 arr1[i] *= arr2[i]; 19 System.out.println(arr1[i]); // 1, 20, 300, 4000, 50000 20 } 21 22 // Arrays.stream(arr1).map(arr -> ...? 23}

###試したこと
Arrays.stream(arr1).map(arr -> ...?

から map メソッドを用いて実装していくべきかと思いましたが、インデックス同士の対応をどのように書いていくべきか思いつけずにおります。
よい書き方ございましたら、ご助言よろしくお願いいたします。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

ベストアンサー

関数型プログラミングが十分に考慮された言語では、二つのストリームをくっつけて一つのストリームにすることをzipという関数で実装しています。たとえば、Scalaであれば、下記のようになります。

Scala

1object SampleZipScala { 2 def main(args: Array[String]): Unit = { 3 val limit = args(0).toInt 4 val st1 = Stream.iterate(1L)(i => i + 1) 5 var st2 = Stream.iterate(1L)(i => i * 10) 6 (st1 zip st2).take(limit).foreach(x => Console.println(x._1 * x._2)) 7 } 8}

※ Int(32bit)だと小さすぎるためLong(64bit)にしています。

Scala以外でもHaskellを始め、C#(というよりLINQ)、Python、Rubyなどよくできていると言われる言語では標準で採用されています。しかし、Java 8ではzip関数は採用されていません。現在開発中の Java 9でも__まだ__採用はされていないようです。Java標準のStreamで将来使えるようになるのかは不明です。

では、どうするかですが、選択肢は4つほどです。

① for文を使う。
一番確実です。Streamを無理に使うのは諦めましょう。Javaを使い続ける限りはこれが一番いいのではないかと思います。

Java

1import java.util.stream.LongStream; 2import java.util.PrimitiveIterator; 3 4class SampleZipJavaFor { 5 public static void main(String[] args) { 6 final int limit = Integer.parseInt(args[0]); 7 final LongStream st1 = LongStream.iterate(1L, i -> i + 1); 8 final LongStream st2 = LongStream.iterate(1L, i -> i * 10); 9 final PrimitiveIterator.OfLong it1 = st1.iterator(); 10 final PrimitiveIterator.OfLong it2 = st2.iterator(); 11 for (int i = 0; i < limit; i++) { 12 System.out.println(it1.nextLong() * it2.nextLong()); 13 } 14 } 15}

② 片方だけSreamにして、もう一方をIteratorにする。
for文なんて使いたくないというのであれば、下記のような書き方もあります。が、余り綺麗とは言えません。

Java

1import java.util.stream.LongStream; 2import java.util.PrimitiveIterator; 3 4class SampleZipJavaForEach { 5 public static void main(String[] args) { 6 final int limit = Integer.parseInt(args[0]); 7 final LongStream st1 = LongStream.iterate(1L, i -> i + 1); 8 final LongStream st2 = LongStream.iterate(1L, i -> i * 10); 9 final PrimitiveIterator.OfLong it = st2.iterator(); 10 st1.limit(limit).forEach(i -> { 11 System.out.println(i * it.nextLong()); 12 }); 13 } 14}

③ zipを実装する、または、zipが実装されたライブラリを使う。
functional programming - Zipping streams using JDK8 with lambda (java.util.stream.Streams.zip) - Stack Overflowに記載の回答など、"Java Stream zip"というキーワードで検索すると色々とサンプルやライブラリが出てきますので、それらのどれかを使うという手段もあります。

④ Javaを捨ててScalaを使う。
このように、JavaのStreamは中途半端です。Streamのような処理のような関数型プログラミングを中心にプログラミングをしたい場合はScalaを使うことをお勧めします。JavaVM環境に縛られていてもScalaはできますし、Javaの遺産との連携もできます。

⑤ JavaVM毎捨てる。
選択肢は自由です。C#も良し、Haskellも良し、PythonだってRubyだって、何だって使えます。Javaの言語設計は今となっては古く、多くの問題をはらんでいると言われています。どうしてもJavaでなければならない事情がなければ、Javaを捨てることをお勧めします。

投稿2016/11/05 10:49

raccy

総合スコア21737

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

JavaTea

2016/11/05 11:09

ありがとうございます。現行の Java8 標準の仕様だけでは、私が考えていたような動作はそもそも無理筋なのですね。 Java8 についての情報を調べて回る中、 for 文禁止などという話も見かけ何とか for 文を使わずに実現できないかと悩んでおりましたが、そもそも Java8 で私の考えていたことを実現しようとするのが無理筋であり、仕様的に無理な実装をなんとか実現出来ないかと無駄に悩んでいたと分かり大変助かりました。 Java の学習はまだ取り掛かったばかりで捨てるのは流石に早すぎな気もしますので、Java の仕様で実現できそうな範囲でループ構造を Stream に書き換えていくことにします。
guest

0

上記のような for ループ同士だとこのようなソースが考えられます

java

1import java.util.*; 2import java.io.*; 3import java.util.stream.*; 4 5import java.util.concurrent.atomic.AtomicInteger; 6class DK{ 7 8 9public static void main(String[] args){ 10 11int limit=5; 12 13int[] arr1 = Stream.iterate(1, i -> i + 1).limit(limit).mapToInt(Integer::intValue).toArray(); 14 15// 1 から 10 倍していく int 配列を作成。 limit が 5 なら {1, 10, 100, 1000, 10000} 16int[] arr2 =Stream.iterate(1, i -> i * 10).limit(limit).mapToInt(Integer::intValue).toArray(); 17 18AtomicInteger i2 = new AtomicInteger(); 19 20 21int[] arr3 =Stream.iterate(1, i -> i*10).limit(limit).mapToInt(Integer::intValue).map(s->s*i2.incrementAndGet()).toArray(); 22 23for(int ar:arr1){ 24 25System.out.println(ar); 26} 27 28 29for(int ar:arr2){ 30 31System.out.println(ar); 32} 33 34 35for(int ar:arr3){ 36 37System.out.println(ar); 38} 39 40} 41 42}

投稿2016/11/05 09:41

退会済みユーザー

退会済みユーザー

総合スコア0

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

JavaTea

2016/11/05 10:51

ご回答誠にありがとうございます。AtomicInteger や incrementAndGet の情報大変参考になりました。 ご教示頂きましたコードで私の例示コードの欲する出力は確かに満たされておりますので、tetratail 様に対しては私の説明力の至らなさをお詫びするほかないのですが、例示コードの arr1, arr2 は for ループ内の動作を分かりやすくするためのサンプル用途として、当座に作成しただけの配列となります。 説明の至りませんでした点を補足させて頂きますと、規則的な値を配置した配列に限らず、任意の値を持つ配列同士でも2つの配列の同インデックス同士が対応していく演算のロジックが書けないものかと悩んでいる次第です。 私の説明の至らなさをお詫びするとともに、ご回答重ねてお礼申し上げます。ありがとうございました。 コード内で説明の足りていない点につきましては速やかに補足し改善いたします。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.37%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問