配列、Mapの操作

「com.cmps.arrayOpe」パッケージを作成し、その中に「ArrayOperation」クラスを作成してください。

Mapのキーや値を取得する(entrySet)

Mapからキーや値を取り出す場合は以下のメソッドを使用します。

// キーを取得
変数名 : Mapの変数名.keySet()
       
// 値を取得
変数名 : Mapの変数名.values()

具体的にコードで書いて試してみましょう。

Map<String, String> country = new HashMap<String, String>();
country.put("USA", "アメリカ");
country.put("Japan", "日本");
country.put("Italy", "イタリア");
       
// キーを取得
for(String en : country.keySet()) {
 System.out.println(en);
}
// 値を取得
for(String ja : country.values()) {
 System.out.println(ja);  
}

keySetメソッド、valuesメソッドでキーと値のそれぞれを取得することが出来ましたが、その両方を取得可能なentrySetメソッドというものもあります。

上で作成した配列のキーと値を取得してみましょう。

// Listとして取得
List<Map.Entry<String, String>> countrySetList = new ArrayList<>(country.entrySet()); // entrySet()でエントリのセットを取得

// キーと値の両方を取得
for(Map.Entry<String, String> entry : countrySetList) { 
 System.out.println(entry.getKey() + ":" + entry.getValue()); // getKey()、getValue()でキーと値を取得し、出力
}

Mapのキーと値のペアはjava.util.Map.Entryインタフェースで表されます。
entrySetメソッドは、このクラスに属する要素を持つマップのコレクション・ビューを返します。

エントリを全て取得するにはentrySetメソッドを使用し、getKeyメソッドでキーを、getValueメソッドで値を取得することができます。

Map.Entryインタフェース
マップのエントリ(キーと値のペア)のことです。
Map.entrySetメソッドは、このクラスに属する要素を持つマップのコレクション・ビューを返します。

Map内に特定のキーが存在するかどうか(containsKey)

containsKeyメソッドは、指定したキーが存在しているか確認し、キーが存在する場合にtrueを返します。

containsKeyメソッド使用例
Map<String, String> sampleMap = new HashMap<String, String>();
sampleMap.put("dog", "犬");
sampleMap.put("cat", "猫");
sampleMap.put("caw", "牛");
        
// sampleMapに「cat」というキーがあるか判定します。
if (sampleMap.containsKey("cat")) {
 System.out.println("キーがありました。");
} else { 
 System.out.println("キーはありませんでした。");
}

配列を結合(arraycopy、concat、addAll)

配列と配列を連結するメソッドは Java では用意されていませんが、以下の方法を用いて配列を結合することが可能です。

Systemクラス

java標準のクラスライブラリのSystemクラスである、arraycopy メソッドを使用して手動で配列と配列を連結して新しい配列を作成することができます。

System.arraycopy (
コピー元配列変数名, コピー元の開始位置,
コピー先配列変数名, コピー先の開始位置,
コピーする要素の数)

このメソッドを使用する場合、コピー元とコピー先の配列を予め用意しておく必要があります。
実際に書いてみましょう。

int[] num = {10,20,30};
int[] dig = {100,200,300};
        
int[] arrayNum = new int[num.length + dig.length]; // 結合先の配列
        
System.arraycopy(num, 0, arrayNum, 0, num.length);
System.arraycopy(dig, 0, arrayNum, num.length, dig.length);

System.out.println(Arrays.toString(arrayNum));

lengthを使いnumとdigの要素数を取得し、それらを足した数の入る配列arrayNumを作成します。
その後、arraycopyを用い、numの要素をコピーし、digをnumのあと(num.length番目)からコピーしています。

Streamクラス

同じく標準のクラスライブラリのStreamクラスを使う方法です。

Stream 変数名 = Stream.concat (Stream変数1,  Stream変数2)
// 配列からStream型へ変換
IntStream streamNum = Arrays.stream(num);
IntStream streamDig = Arrays.stream(dig);

// Streamクラスのconcatメソッドで結合
IntStream join = IntStream.concat(streamNum, streamDig);

// toArrayメソッドで配列へ変換
int[] arrayStream = join.toArray();
System.out.println(Arrays.toString(arrayStream));

Arrays.stream(array)を使うと、指定した配列をStream形式に変換でき、ストリーム操作が可能になります。

そしてconcatメソッドを使用し、stream1の後ろにstreamDigを結合したjoinという新たなストリームを作成し、toArrayメソッドで配列へ再度変換を行います。

ArrayUtilsクラス

3つ目が、Apache Common LangのArrayUtilsというクラスを使う方法です。

型名[] 結合後の配列型変数 = ArrayUtils.addAll (配列型変数1, 配列型変数2)
//  ArrayUtilsクラス
int[] util = ArrayUtils.addAll(num, dig);
System.out.println(Arrays.toString(util));

addAllメソッドが新たに配列を作ってくれるため、これまでの2つと異なり、結合した結果を入れる配列を準備する必要はありません。そのため、上記3つの中では最もシンプルな記述となります。

しかし、前提としてApache Commons Langのライブラリをダウンロードして、Javaの開発環境に取り込んでおくことが必要です。
記述しただけではエラーが発生すると思いますので、コメントアウトしてもらっても大丈夫です。

出力結果はどれも以下のようになるかと思います。

[10, 20, 30, 100, 200, 300]
[10, 20, 30, 100, 200, 300]
[10, 20, 30, 100, 200, 300]

Mapの結合

List の場合は単に合わせれば良いのですが、Map の場合 key は同じですが value が異なる値が 2 つの Map にあるときにどの value を使用するかを設定しなければならない場合があります。

putAll()

putAllとは、指定したマップから全てのマッピングをコピーします。キーの一致する場合はコピー元の値に置き換わり、既存のマップにキーが存在しない場合は追加されます。

既存のマップ.putAll(コピーするマップ);

既存のマップに存在するキーの値はコピーするマップの値に上書きされ、既存マップの存在しないキーの値はコピーするマップのキーと値が追加されます。

Map<String, Integer> fruitsMap = new HashMap<String, Integer>();
fruitsMap.put("リンゴ",100 );
fruitsMap.put("オレンジ",200 );
        
Map<String, Integer> fruitsMap2 = new HashMap<String, Integer>();
fruitsMap2.put("桃",400 );
fruitsMap2.put("リンゴ",200 );
        
fruitsMap.putAll(fruitsMap2);
System.out.println(fruitsMap);

上記の例では、fruitsMapにfruitsmap2の全ての要素を追加しています。

{桃=400, リンゴ=200, オレンジ=200}

fruitsMapの持っていた「リンゴ」のvalueはfruitsMap2のvalueによって上書きされました。

merge()

mergeはクセのあるメソッドで、引数のkeyがmapに存在するときとしないときで違う動きをします。

Map<String,String> animalMap = new HashMap<String, String>();
animalMap.put("アフリカ", "アミメ");
animalMap.put("日本", "タヌキ");
        
animalMap.merge("アフリカ", "キリン", String::concat);
animalMap.merge("アメリカ", "ピューマ", String::concat);
System.out.println(animalMap);

一度目のmergeでは指定されたkey「アフリカ」がmapに存在するため、再マッピング関数(String::concat-文字列を結合する)が実行され現在のvalueに引数のvalueを結合した値が再マッピングされます。

一方で、二度目のmergeで指定されたkey「アメリカ」はmapに存在しないため、新しくマッピングされます。
その際、再マッピング関数は無視されます。

出力結果は以下の通りです。

{アメリカ=ピューマ, 日本=タヌキ, アフリカ=アミメキリン}

練習問題

「com.cmps.arrayOpe」パッケージ内に「ArrayOperationQuestion」クラスを作成してください。

問1:「tokyo」というキーが存在した場合、「東京!」と表示する。

問2:適当な配列を二つ用意して結合してください。

問3:適当な連想配列を二つ用意して結合してください。キーはかぶらない前提!

問4:適当な多次元連想配列を二つ用意して合わせてください。

問5:都道府県をキーとし値に県庁所在地が格納された配列を作成して三番目を表示してください。都道府県は5つまで

練習問題のヒント
問5
「3番目」という順番が必要な情報となるので、要素の挿入順が保持されるLinkedHashMapを使用して配列を作成します。
作成後、entrySetメソッドを使いArrayListへ変換し、リストとして扱えるようにしてから、3番目をgetメソッドで取得し、新たなMap.Entryクラスの変数に格納して出力しましょう。

タイトルとURLをコピーしました