【Java Stream API 超入門】 多重リストを纏めるflatMapと重複の削除を行うdistinct

こんにちは。大城です。
 
本ブログでは、Java SE 8で追加されたStream APIについて、初心者向けに解説していきます。
 
前回のブログでは、絞り込みや要素の変換などを行う中間処理filtermapについて紹介しました。中間処理2回目の今回は、flatMapdistinctについて紹介していきます。

環境

OS
Windows10
Java
Java8

多重リストを纏めるときに使えるflatMap

前回紹介したmapメソッドと同様に、要素の変換を行うメソッドですが、変換後の型としてStreamを指定します。
 

public class Main {
	public static void main(String[] args) {
				
		List<List<String>> list = new ArrayList<>(Arrays.asList(
				Arrays.asList("Tokyo", "Chiba"),
				Arrays.asList("Saitama", "Kanagawa", "Gunma"),
				Arrays.asList("Tochigi", "Ibaraki", "Yamanashi")));

		System.out.println("------元のlistの内容------");
		list.stream()
			.forEach(l -> System.out.println(l));

		System.out.println("");
		System.out.println("------flatMapにより纏めた結果------");
		list.stream()
			.flatMap(l -> l.stream())
			.forEach(e -> System.out.println(e));
	}
}

実行結果
------元のlistの内容------
[Tokyo, Chiba]
[Saitama, Kanagawa, Gunma]
[Tochigi, Ibaraki, Yamanashi]

------flatMapにより纏めた結果------
Tokyo
Chiba
Saitama
Kanagawa
Gunma
Tochigi
Ibaraki
Yamanashi

flatMapで纏めた結果、もともと二重のリストの構造をとっていたlistの内容が纏められていることがわかります。
 
15行目のラムダ式で、StringのListのlを、そのままStreamに変換しています。flatMapでは、mapと違いStreamに変換するように指定します。
 
mapでは変換後の要素をすべて集めたStreamを返しますが、flatMapではStreamに変換後に全てをつなげたStreamを返り値として返します。
 
少し複雑な例もご紹介します。
class Prefecture {
	private String name;
	
	private List<String> cities;

	public Prefecture(String name, List<String> cities) {
		this.name = name;
		this.cities = cities;
	}
	
	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public List<String> getCities() {
		return cities;
	}

	public void setCities(List<String> cities) {
		this.cities = cities;
	}
}

public class Main2 {
	public static void main(String[] args) {
		
		List<Prefecture> prefectureList = new ArrayList<>(Arrays.asList(
				new Prefecture("Tokyo", Arrays.asList("chiyoda-ku", "chuo-ku", "minato-ku", "sinjuku-ku")),
				new Prefecture("Chiba", Arrays.asList("chiba-shi", "choshi-shi", "ichikawa-shi")),
				new Prefecture("Saitama", Arrays.asList("saitama-shi", "kawagoe-shi", "kumagaya-shi"))
		));
		
		System.out.println("------mapによりPrefectureをStringのListに変換した結果------");
		prefectureList.stream()
			.map(l -> l.getCities())
			.forEach(e -> System.out.println(e));
		
		System.out.println("");
		System.out.println("------flatMapでStringのListのStreamを纏めた結果------");
		prefectureList.stream()
			.flatMap(l -> l.getCities().stream())
			.forEach(e -> System.out.println(e));
	}
}

実行結果
------mapによりPrefectureをStringのListに変換した結果------
[chiyoda-ku, chuo-ku, minato-ku, sinjuku-ku]
[chiba-shi, choshi-shi, ichikawa-shi]
[saitama-shi, kawagoe-shi, kumagaya-shi]

------flatMapでStringのListのStreamを纏めた結果------
chiyoda-ku
chuo-ku
minato-ku
sinjuku-ku
chiba-shi
choshi-shi
ichikawa-shi
saitama-shi
kawagoe-shi
kumagaya-shi

PrefectureクラスのメンバcitiesはStringのListです。
 
44行目のl.getCities().stream()ではStreamを返すので、flatMapでそれらをすべて纏めたStreamを取得しています。

重複の削除を行うdistinct

続いてdistinctメソッドについて説明します。
例をご覧ください。

public class Main {

	public static void main(String[] args) {

		List<String> list = Arrays.asList("Tokyo", "Chiba", "Saitama", "Tokyo", "Kanagawa", "Saitama", "Gunma", "Tokyo");
		
		System.out.println("------重複削除を行う前------");
		list.stream()
			.forEach(e -> System.out.println(e));
		
		System.out.println("------distinctによる重複削除実行結果------");
		list.stream()
			.distinct()
			.forEach(e -> System.out.println(e));
	}
}

実行結果
------重複削除を行う前------
Tokyo
Chiba
Saitama
Tokyo
Kanagawa
Saitama
Gunma
Tokyo
------distinctによる重複削除実行結果------
Tokyo
Chiba
Saitama
Kanagawa
Gunma

重複登録した要素が削除されていることが確認できます。

まとめ

いかがでしたか。
flatMapは少し分かりづらいですが、多重配列を1次元の配列に纏めるのは使いやすい機能なのではないかと思います。いずれのメソッドも役立つ機会は多いと思うのでぜひ使ってみてください。
 
次回では、ソートなどの中間処理メソッドについて解説していこうと思います。
 
それでは、また。
 
 
 
《関連記事》

記事をシェア
MOST VIEWED ARTICLES