当サイトは、アフィリエイト広告を利用しています

【java8】streamを使用して二つのlistを突合せる方法

作成日:2022月03月01日
更新日:2024年03月28日

従来は for 文の二重ループなどを使って突合せをしていたがjava8の
streamのflatMap等を使用して行うことができた。 2個のListを突き合わせて

  • 2個のListうち一致しているオブジェクトのみのListまたは配列を作る
  • 2個のListで一致しているオブジェクトの値のみを固定値で更新する
  • 2個のListで一致しているオブジェクトの値のみを一致したオブジェクトの値で更新する

を行う方法をそれぞれまとめる。

2個のListうち一致しているオブジェクトのみのListまたは配列を作る

2個の配列やListを突き合わせて指定した条件に一致しているもののみのListを新しく作る。
flatMap内でfilterを使って実現する。

Personクラス

サンプルオブジェクトクラス。
ここより下記のソースではすべてこのクラスのインスタンスを使用する。

Person.java
//サンプルオブジェクトクラス
class Person{
// 名前
String name;
String firstName;
// セッター
void setName(String name){
this.name = name;
}
// ゲッター
String getName(){
return this.name;
}
void setFirstName(String firstName){
this.firstName = firstName;
}
// ゲッター
String getFirstName(){
return this.firstName;
}
@Override
public String toString()
{
return "{" + "name : "+ this.name + ", " + "firstName : " + this.firstName + "}";
}
}
  • オブジェクトの中身が出力されるようにtoStringメソッドをオーバーライドする

オブジェクトの中身出力については下記の記事で紹介しています。

配列の場合

二つの配列を突合せするパターン。
strermAPIのflatMapとfilterを使って実現する

配列
import java.util.*;
import java.util.stream.Collectors;
public class Main {
public static void main(String[] args) throws Exception {
// Your code here!
List<String>strList1 = Arrays.asList("1","2","3","4","5","6");
List<String>strList2 = Arrays.asList("2","5","6");
// 突合せ処理
List<String>muchList = strList1.stream()
.flatMap(
str1val -> strList2.stream()
.filter(
str2val -> str1val.equals(str2val)
)
).collect(Collectors.toList());
System.out.println(muchList);
}
}
// 結果
// 二つのlistの一致してる値だけのlistができる
// muchList :2,5,6

オブジェクトのListの場合

streamのflatMapとfilterメソッドを使って下記の2個のList

  • マスタList
  • トランザクションList

を突き合わせて、指定した条件に一致したオブジェクトのみのListを作る。

オブジェクトのList
import java.util.*;
import java.util.stream.Collectors;
public class Main {
public static void main(String[] args) throws Exception {
// 突き合わせるList
List<Person>mstList = new ArrayList<>();
List<Person>trnList = new ArrayList<>();
// マスタListに値を詰める
for(int i=0;i<5;i++){
Person personObj1 = null;
personObj1 = new Person();
personObj1.setName(String.valueOf(i) + "takashi");
mstList.add(personObj1);
}
// マスタList確認
System.out.println("【マスタList】");
mstList.stream().forEach(ob1 ->{
System.out.println(ob1);
}
);
System.out.println("");
// トランザクションListに値を詰める
for(int i=2;i<10;i++){
Person personObj2 = null;
personObj2 = new Person();
personObj2.setName(String.valueOf(i) + "takashi");
personObj2.setFirstName(String.valueOf(i) + "tanaka");
trnList.add(personObj2);
}
// トランザクションList確認
System.out.println("【トランザクションList】");
trnList.stream().forEach(ob2 ->{
System.out.println(ob2);
}
);
System.out.println("");
// 突合せ処理
List<Person>resultList = mstList.stream()
.flatMap(
mstObj -> trnList.stream()
.filter(
trnObj -> mstObj.getName().equals(trnObj.getName())
)
).collect(Collectors.toList());
// 突合せ結果
System.out.println("【nameが一致したオブジェクトList】");
resultList.stream().forEach(muchObj ->
System.out.println(muchObj)
);
}
}

実行結果を確認する

実行結果
【マスタList】
{name : 0takashi, firstName : null}
{name : 1takashi, firstName : null}
{name : 2takashi, firstName : null}
{name : 3takashi, firstName : null}
{name : 4takashi, firstName : null}
【トランザクションList】
{name : 2takashi, firstName : 2tanaka}
{name : 3takashi, firstName : 3tanaka}
{name : 4takashi, firstName : 4tanaka}
{name : 5takashi, firstName : 5tanaka}
{name : 6takashi, firstName : 6tanaka}
{name : 7takashi, firstName : 7tanaka}
{name : 8takashi, firstName : 8tanaka}
{name : 9takashi, firstName : 9tanaka}
【nameが一致したオブジェクトList】
{name : 2takashi, firstName : 2tanaka}
{name : 3takashi, firstName : 3tanaka}
{name : 4takashi, firstName : 4tanaka}

【nameが一致したオブジェクトList】が取得できている。
一致した場合にresultListに格納されるのはfilterでループしてる方のオブジェクトになる。
※この例だとトランザクションList(trnList)のオブジェクト。

動作確認したオンラインソースを下記に載せます。

オブジェクトList_matching

省略なしで書いたver

上記はstream内を省略したので省略なしで書いてみる

flatMapで突き合わせ(省略なし)
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public class Main {
public static void main(String[] args) throws Exception {
// 突き合わせるList
List<Person>mstList = new ArrayList<>();
List<Person>trnList = new ArrayList<>();
// マスタListに値を詰める
for(int i=0;i<5;i++){
Person personObj1 = null;
personObj1 = new Person();
personObj1.setName(String.valueOf(i) + "takashi");
mstList.add(personObj1);
}
// マスタList確認
System.out.println("【マスタList】");
mstList.stream().forEach(ob1 ->{
System.out.println(ob1);
}
);
System.out.println("");
// トランザクションListに値を詰める
for(int i=2;i<10;i++){
Person personObj2 = null;
personObj2 = new Person();
personObj2.setName(String.valueOf(i) + "takashi");
personObj2.setFirstName(String.valueOf(i) + "tanaka");
trnList.add(personObj2);
}
// トランザクションList確認
System.out.println("【トランザクションList】");
trnList.stream().forEach(ob2 ->{
System.out.println(ob2);
}
);
System.out.println("");
//突合せ処理(省略なし)
List<Person>resultList = mstList.stream()
.flatMap(
mstObj -> {
Stream<Person>streamList = trnList.stream().filter(trnObj -> mstObj.getName().equals(trnObj.getName()));
return streamList;
}).collect(Collectors.toList());
// 突合せ結果
System.out.println("【一致したオブジェクトのList】");
resultList.stream().forEach(muchObj ->
System.out.println(muchObj)
);
}
}

実行結果を確認する

実行結果
【マスタList】
{name : 0takashi, firstName : null}
{name : 1takashi, firstName : null}
{name : 2takashi, firstName : null}
{name : 3takashi, firstName : null}
{name : 4takashi, firstName : null}
【トランザクションList】
{name : 2takashi, firstName : 2tanaka}
{name : 3takashi, firstName : 3tanaka}
{name : 4takashi, firstName : 4tanaka}
{name : 5takashi, firstName : 5tanaka}
{name : 6takashi, firstName : 6tanaka}
{name : 7takashi, firstName : 7tanaka}
{name : 8takashi, firstName : 8tanaka}
{name : 9takashi, firstName : 9tanaka}
【一致したオブジェクトのList】
{name : 2takashi, firstName : 2tanaka}
{name : 3takashi, firstName : 3tanaka}
{name : 4takashi, firstName : 4tanaka}
  • 結果は同じ。

flatMapが何をしているか?

flatMapが何をしているのかを少し調べて見る
試しにflatMapではなくmapを使ってみる

実行クラス

mapを使ってmap内のfilterの戻り値に何が帰ってきているかを調べる。

mapで検証
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public class Main {
public static void main(String[] args) throws Exception {
// 突き合わせるList
List<Person>mstList = new ArrayList<>();
List<Person>trnList = new ArrayList<>();
// マスタListに値を詰める
for(int i=0;i<5;i++){
Person personObj1 = null;
personObj1 = new Person();
personObj1.setName(String.valueOf(i) + "takashi");
mstList.add(personObj1);
}
// マスタList確認
System.out.println("【マスタList】");
mstList.stream().forEach(ob1 ->{
System.out.println(ob1);
}
);
System.out.println("");
// トランザクションListに値を詰める
for(int i=2;i<10;i++){
Person personObj2 = null;
personObj2 = new Person();
personObj2.setName(String.valueOf(i) + "takashi");
personObj2.setFirstName(String.valueOf(i) + "tanaka");
trnList.add(personObj2);
}
// トランザクションList確認
System.out.println("【トランザクションList】");
trnList.stream().forEach(ob2 ->{
System.out.println(ob2);
}
);
System.out.println("");
// 突合せ処理(mapで確認してみる)
//mapの結果はlistlistで帰ってきているため、flatMapで次元をあげてやる必要がある
//coListはListListには変換できない
List<Object> resultList = mstList.stream()
.map(
mstObj -> {
Stream<Person>streamList = trnList.stream().filter(trnObj -> mstObj.getName().equals(trnObj.getName()));
System.out.println("【stream内のfilterの結果】: " + streamList.collect(Collectors.toList()));
return streamList;
}
).collect(Collectors.toList());
}
}

実行結果を確認する

実行結果
【マスタList】
{name : 0takashi, firstName : null}
{name : 1takashi, firstName : null}
{name : 2takashi, firstName : null}
{name : 3takashi, firstName : null}
{name : 4takashi, firstName : null}
【トランザクションList】
{name : 2takashi, firstName : 2tanaka}
{name : 3takashi, firstName : 3tanaka}
{name : 4takashi, firstName : 4tanaka}
{name : 5takashi, firstName : 5tanaka}
{name : 6takashi, firstName : 6tanaka}
{name : 7takashi, firstName : 7tanaka}
{name : 8takashi, firstName : 8tanaka}
{name : 9takashi, firstName : 9tanaka}
【stream内のfilterの結果】: []
【stream内のfilterの結果】: []
【stream内のfilterの結果】: [{name : 2takashi, firstName : 2tanaka}]
【stream内のfilterの結果】: [{name : 3takashi, firstName : 3tanaka}]
【stream内のfilterの結果】: [{name : 4takashi, firstName : 4tanaka}]

stream内で実行されているfilterの戻り値がListであることがわかる。
つまりmapの戻り値としては下記のようにList< List < Person >>の形になっている。

stream内のfilterの結果
[
[],
[],
[],
[{name : 2takashi, firstName : 2tanaka}],
[{name : 3takashi, firstName : 3tanaka}],
[{name : 4takashi, firstName : 4tanaka}],
]

このままではList< Person >型では受け取れないので
flatMapで平坦にして受け取っている。
イメージとしては下記のような感じになる。

flatMapで平坦した場合
[
{name : 2takashi, firstName : 2tanaka},
{name : 3takashi, firstName : 3tanaka},
{name : 4takashi, firstName : 4tanaka},
]

flatMapで中のList< List < Person >>を一次元あげて、
List < Person >で受け取れるようにしている

mapで動作確認したオンラインソースを載せときます。

mapで検証

2個のListで一致しているオブジェクトの値のみを固定値で更新する

streamのmapとanyMatchメソッドを使って下記の2個のList

  • マスタList
  • トランザクションList

を突き合わせて、指定した条件に一致した場合に
固定値でマスタListのオブジェクトを更新する

anyMatchで突き合わせ
import java.util.*;
import java.util.stream.Collectors;
public class Main {
public static void main(String[] args) throws Exception {
// 突き合わせるList
List<Person>mstList = new ArrayList<>();
List<Person>trnList = new ArrayList<>();
// マスタListに値を詰める
for(int i=0;i<5;i++){
Person personObj1 = null;
personObj1 = new Person();
personObj1.setName(String.valueOf(i) + "takashi");
mstList.add(personObj1);
}
// マスタList確認
System.out.println("【マスタList】");
mstList.stream().forEach(ob1 ->{
System.out.println(ob1);
}
);
System.out.println("");
// トランザクションListに値を詰める
for(int i=2;i<10;i++){
Person personObj2 = null;
personObj2 = new Person();
personObj2.setName(String.valueOf(i) + "takashi");
personObj2.setFirstName(String.valueOf(i) + "tanaka");
trnList.add(personObj2);
}
// トランザクションList確認
System.out.println("【トランザクションList】");
trnList.stream().forEach(ob2 ->{
System.out.println(ob2);
}
);
System.out.println("");
// 突合せ更新処理(固定値)
List<Person>resultList = mstList.stream()
.map(mstObj -> {
//トランザクションListを検索する
boolean result = trnList.stream().anyMatch(trnObj -> mstObj.getName().equals(trnObj.getName()));
if(result){
mstObj.setName("一致");
}
return mstObj;
}).collect(Collectors.toList());
// 突合せ固定値更新結果
System.out.println("【更新後マスタList】");
resultList.stream().forEach(muchObj ->
System.out.println(muchObj)
);
}
}
  • streamのmap内でanyMatchを使用する。
  • トランザクションListの検索条件として「name」を指定
  • anyMatchがtrueの場合(一致しているものが見つかった場合)のみ固定値で更新する。

実行結果を確認する

実行結果
【マスタList】
{name : 0takashi, firstName : null}
{name : 1takashi, firstName : null}
{name : 2takashi, firstName : null}
{name : 3takashi, firstName : null}
{name : 4takashi, firstName : null}
【トランザクションList】
{name : 2takashi, firstName : 2tanaka}
{name : 3takashi, firstName : 3tanaka}
{name : 4takashi, firstName : 4tanaka}
{name : 5takashi, firstName : 5tanaka}
{name : 6takashi, firstName : 6tanaka}
{name : 7takashi, firstName : 7tanaka}
{name : 8takashi, firstName : 8tanaka}
{name : 9takashi, firstName : 9tanaka}
【更新後マスタList】
{name : 0takashi, firstName : null}
{name : 1takashi, firstName : null}
{name : 一致, firstName : null}
{name : 一致, firstName : null}
{name : 一致, firstName : null}

一致しているnameが更新されたオブジェクトのListが取得できる。
streamのanyMatchの使い方については下記記事で紹介しています!

実際に動かしてみたオンラインソースを下記に載せます。

anyMatchで突き合わせ

2個のListで一致しているオブジェクトの値のみを一致したオブジェクトの値で更新する

streamのmap,filter,findfirstメソッドを使って2個のList

  • マスタList
  • トランザクションList

を突き合わせて、指定した条件に一致した場合に一致したトランザクションListのオブジェクトの値で
マスタListのオブジェクトの値を更新する。

anyMatchでは結果はboolean型で返却されるため、
一致したオブジェクトまではわからなかったが
filterとfindfirstを使うことで一致したオブジェクトを特定することができる。

突き合わせ実行クラス

突き合わせを実行するクラス

findfistで突き合わせ
import java.util.*;
import java.util.stream.Collectors;
public class Main {
public static void main(String[] args) throws Exception {
// 突き合わせるList
List<Person>mstList = new ArrayList<>();
List<Person>trnList = new ArrayList<>();
// マスタListに値を詰める
for(int i=0;i<5;i++){
Person personObj1 = null;
personObj1 = new Person();
personObj1.setName(String.valueOf(i) + "takashi");
mstList.add(personObj1);
}
// マスタList確認
System.out.println("【マスタList】");
mstList.stream().forEach(ob1 ->{
System.out.println(ob1);
}
);
System.out.println("");
// トランザクションListに値を詰める
for(int i=2;i<10;i++){
Person personObj2 = null;
personObj2 = new Person();
personObj2.setName(String.valueOf(i) + "takashi");
personObj2.setFirstName(String.valueOf(i) + "tanaka");
trnList.add(personObj2);
}
// トランザクションList確認
System.out.println("【トランザクションList】");
trnList.stream().forEach(ob2 ->{
System.out.println(ob2);
}
);
System.out.println("");
// 突合せ更新処理(オブジェクトの値)
List<Person>resultList = mstList.stream()
.map(mstObj -> {
//トランザクションListを検索する
Person result = trnList.stream().filter(trnObj -> mstObj.getName().equals(trnObj.getName())).findFirst().orElse(null);
if(Objects.nonNull(result)){
//一致してる場合更新
mstObj.setFirstName(result.getFirstName());
}
return mstObj;
}).collect(Collectors.toList());
// 突合せ更新結果
System.out.println("【更新後マスタList】");
resultList.stream().forEach(muchObj ->
System.out.println(muchObj)
);
}
}
  • map内でfilterとfindFirstを使ってオブジェクトを検索。
  • 発見できた場合はそのオブジェクトのfirstNameでマスタListのオブジェクトを更新する

実行結果を確認する

log
【マスタList】
{name : 0takashi, firstName : null}
{name : 1takashi, firstName : null}
{name : 2takashi, firstName : null}
{name : 3takashi, firstName : null}
{name : 4takashi, firstName : null}
【トランザクションList】
{name : 2takashi, firstName : 2tanaka}
{name : 3takashi, firstName : 3tanaka}
{name : 4takashi, firstName : 4tanaka}
{name : 5takashi, firstName : 5tanaka}
{name : 6takashi, firstName : 6tanaka}
{name : 7takashi, firstName : 7tanaka}
{name : 8takashi, firstName : 8tanaka}
{name : 9takashi, firstName : 9tanaka}
【更新後マスタList】
{name : 0takashi, firstName : null}
{name : 1takashi, firstName : null}
{name : 2takashi, firstName : 2tanaka}
{name : 3takashi, firstName : 3tanaka}
{name : 4takashi, firstName : 4tanaka}

マスタListの中でトランザクションListのオブジェクトのnameと
一致しているオブジェクトのfirstNameが一致しているトランザクションListの
オブジェクトのfirstNameで更新されている。

動作確認したオンラインソースを下記の載せます。

findfistで突き合わせ

注意点

トランザクションListから指定した条件に一致しているオブジェクトを探す際
findfirstを使用しているため、トランザクションListに指定した条件に当てはまる
オブジェクトが複数存在する場合は、最初に見つかった方しか取得できない。
そのため指定する条件はユニークにする必要がある。

findFirstの使い方については下記記事で紹介しています!

書籍紹介

下記の本ではjava8のstreamについて詳しく記載があるのでおすすめです。

新着記事

タグ別一覧
top