Javaにおける配列操作
1.概要
Java開発者は誰でも、配列操作を扱うときにクリーンで効率的なソリューションを作成することが必ずしも容易ではないことを知っています。それでも、それらはJavaエコシステムの中心的な部分です – そして、私たちは何度かそれらに対処しなければなりません。
このため、「チートシート」 – パズルにすばやく取り組むのに役立つ最も一般的な手順の概要 – を入手することをお勧めします。このチュートリアルはそのような状況で役に立ちます。
2.配列とヘルパークラス
先に進む前に、Javaの配列とは何か、またその使い方を理解しておくと便利です。 Javaで初めて作業する場合は、https://www.baeldung.com/java-arrays-guide[この記事]で、基本的な概念をすべて説明してください。
配列がサポートする基本操作は、ある意味で制限されていることに注意してください。配列に関しては、比較的単純なタスクを実行するために複雑なアルゴリズムを使用することは珍しくありません。
-
このため、ほとんどのオペレーションでは、ヘルパークラスとメソッドを使用して支援しています。
Javaが提供するhttps://www.baeldung.com/java-util-arrays[
Arrays
]クラスとApacheのhttps://www.baeldung.com/array-processing-commons-lang[
ArrayUtils
]クラス
後者を私たちのプロジェクトに含めるためには、https://commons.apache.org/[Apache Commons]依存関係を追加する必要があります。
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.8.1</version>
</dependency>
このアーティファクトの最新版をチェックすることができます。 %22(Maven Central上)
3.配列の最初と最後の要素を取得する
これは、索引によるアクセスによる性質のため、最も一般的で単純なタスクの1つです。
すべての例で使用される
int
配列を宣言して初期化することから始めましょう(特に指定しない限り)。
int[]array = new int[]{ 3, 5, 2, 5, 14, 4 };
配列の最初の項目がインデックス値0に関連付けられていて、使用できる
length
属性を持っていることを知っているので、これら2つの要素を取得する方法を理解するのは簡単です。
int firstItem = array[0];
int lastItem = array[array.length - 1];
4.配列からランダムな値を取得する
java.util.Random
オブジェクトを使用することで、配列から任意の値を簡単に取得できます。
int anyValue = array[new Random().nextInt(array.length)];
5.新しい項目を配列に追加する
ご存じのとおり、配列は固定サイズの値を保持します。したがって、アイテムを追加してこの制限を超えることはできません。
まず、新しい、より大きい配列を宣言し、基本配列の要素を2番目の要素にコピーする必要があります。
幸い、
Arrays
クラスは、配列の値を新しいサイズの異なる構造体に複製するための便利なメソッドを提供します。
int[]newArray = Arrays.copyOf(array, array.length + 1);
newArray[newArray.length - 1]= newItem;
-
オプションで、
ArrayUtils
クラスが私たちのプロジェクトでアクセス可能であれば、1行ステートメントで目的を達成するために
addメソッド
(またはその
addAll
alternative)を利用することができます。
int[]newArray = ArrayUtils.add(array, newItem);
想像できるように、このメソッドは元の
array
オブジェクトを変更しません。その出力を新しい変数に代入する必要があります。
6. 2つの値の間に値を挿入する
その添字付き文字のため、他の2つの間の配列に項目を挿入することは簡単な仕事ではありません。
Apacheはこれを典型的なシナリオと見なし、ソリューションを単純化するために
ArrayUtils
クラスにメソッドを実装しました。
int[]largerArray = ArrayUtils.insert(2, array, 77);
値を挿入するインデックスを指定する必要があります。出力は、多数の要素を含む新しい配列になります。
最後の引数は可変引数(別名
vararg
)なので、配列には任意の数の項目を挿入できます。
7. 2つの配列を比較する
配列は
__Object
sであり、したがって
equals__メソッドを提供しますが、それらはデフォルトの実装を使用し、参照の等価性のみに依存します。
とにかく
java.util.Arrays
equals
メソッドを呼び出して、2つの配列オブジェクトに同じ値が含まれているかどうかを確認できます。
boolean areEqual = Arrays.equals(array1, array2);
注:この方法はhttps://www.baeldung.com/java-jagged-arrays[jagged array]には効果がありません。多次元構造の等価性を検証するための適切な方法は
Arrays.deepEquals
です。
8.配列が空かどうか調べる
これは、配列の
length
属性を使用できることを念頭に置いているので、単純な代入です。
boolean isEmpty = array == null || array.length == 0;
さらに、
ArrayUtils
ヘルパークラスにnull-safeメソッドもあります。
boolean isEmpty = ArrayUtils.isEmpty(array);
-
この関数は依然としてデータ構造の長さに依存します。これはnullと空のサブ配列も有効な値と見なすため、次のようなエッジケースに注意する必要があります。
----//These are empty arrays
Integer[]array1 = {};
Integer[]array2 = null;
Integer[]array3 = new Integer[0];
//All these will NOT be considered empty
Integer[]array3 = { null, null, null };
Integer[][]array4 = { {}, {}, {} };
Integer[]array5 = new Integer[3];
----
9.配列の要素をシャッフルする方法
配列内のアイテムをシャッフルするために、
ArrayUtil
‘s機能を使用できます。
ArrayUtils.shuffle(array);
-
これは
void
メソッドで、配列の実際の値に作用します。
10.ボックスとアンボックスの配列
オブジェクトベースの配列のみをサポートするメソッドに出会うことがよくあります。
ここでも、
ArrayUtils
ヘルパークラスが、ボックス化バージョンのプリミティブ配列を取得するのに便利です。
Integer[]list = ArrayUtils.toObject(array);
逆の操作も可能です。
Integer[]objectArray = { 3, 5, 2, 5, 14, 4 };
int[]array = ArrayUtils.toPrimitive(objectArray);
11.配列から重複を削除する
重複を削除する最も簡単な方法は、配列を
Set
実装に変換することです。
ご存知かもしれませんが、
__Collection
__はGenericsを使用しているため、プリミティブ型をサポートしていません。
このため、この例のようにオブジェクトベースの配列を処理しない場合は、まず値をボックス化する必要があります。
----//Box
Integer[]list = ArrayUtils.toObject(array);//Remove duplicates
Set<Integer> set = new HashSet<Integer>(Arrays.asList(list));//Create array and unbox
return ArrayUtils.toPrimitive(set.toArray(new Integer[set.size()]));
----
注:https://www.baeldung.com/convert-array-to-set-and-set-to-array[配列と
Set
オブジェクト間で変換するための他の手法]も使用できます。
また、要素の順序を保持する必要がある場合は、
LinkedHashSet
などの異なる
Set
実装を使用する必要があります。
12.配列を印刷する方法
equals
メソッドと同様に、配列の
toString
関数は
Object
クラスによって提供されるデフォルトの実装を使用しますが、これはあまり役に立ちません。
Arrays
と
__ArrayUtilsの両方のクラスは、データ構造を読み取り可能な
String__に変換するための実装とともに出荷されます。
それらが使用するわずかに異なるフォーマットは別として、最も重要な違いはそれらが多次元オブジェクトをどのように扱うかです。
Java Utilのクラスには、使用できる2つの静的メソッドがあります。
-
toString
:ギザギザ配列ではうまく機能しません -
deepToString
:任意の
Object
ベースの配列をサポートしますが、しません
プリミティブ配列引数でコンパイルする
一方、Apacheの実装は、どのような場合でも正しく機能する単一の
toString
メソッドを提供します。
String arrayAsString = ArrayUtils.toString(array);
13.配列を他の型にマップする
すべての配列項目に操作を適用し、場合によってはそれらを別の種類のオブジェクトに変換すると便利なことがよくあります。
この目的を念頭に置いて、Genericsを使用して柔軟なヘルパーメソッドを作成しようとしています。
public static <T, U> U[]mapObjectArray(
T[]array, Function<T, U> function,
Class<U> targetClazz) {
U[]newArray = (U[]) Array.newInstance(targetClazz, array.length);
for (int i = 0; i < array.length; i++) {
newArray[i]= function.apply(array[i]);
}
return newArray;
}
プロジェクトでJava 8を使用しない場合は、
Function
引数を破棄して、実行する必要があるマッピングごとにメソッドを作成できます。
これで、私たちの一般的な方法をさまざまな操作に再利用できます。これを説明するために、2つのテストケースを作成しましょう。
@Test
public void whenMapArrayMultiplyingValues__thenReturnMultipliedArray() {
Integer[]multipliedExpectedArray = new Integer[]{ 6, 10, 4, 10, 28, 8 };
Integer[]output =
MyHelperClass.mapObjectArray(array, value -> value ** 2, Integer.class);
assertThat(output).containsExactly(multipliedExpectedArray);
}
@Test
public void whenMapDividingObjectArray__thenReturnMultipliedArray() {
Double[]multipliedExpectedArray = new Double[]{ 1.5, 2.5, 1.0, 2.5, 7.0, 2.0 };
Double[]output =
MyHelperClass.mapObjectArray(array, value -> value/2.0, Double.class);
assertThat(output).containsExactly(multipliedExpectedArray);
}
プリミティブ型の場合は、最初に値を入力する必要があります。
-
代わりに、マッピングを実行するためにhttps://www.baeldung.com/java-8-streams-introduction[Java 8’s Streams]にアクセスすることもできます。**
まず配列を
__Object
sの
Stream__に変換する必要があります。
Arrays.stream
メソッドを使ってそうすることができます。
たとえば、
int
値をカスタムの
String
表現にマッピングする場合は、次のように実装します。
String[]stringArray = Arrays.stream(array)
.mapToObj(value -> String.format("Value: %s", value))
.toArray(String[]::new);
14.配列内の値をフィルタする
コレクションから値を除外することは、私たちが複数回実行しなければならない可能性がある一般的なタスクです。
これは、値を受け取る配列を作成する時点では、最終的なサイズがわからないためです。したがって、
__Stream
__sアプローチに再び依存します。
配列からすべての奇数を削除したいとします。
int[]evenArray = Arrays.stream(array)
.filter(value -> value % 2 == 0)
.toArray();
15.その他の一般的な配列操作
もちろん、他にもたくさんの配列操作が必要になるかもしれません。
このチュートリアルに示されているものとは別に、私たちは専用の投稿で他の操作を広くカバーしています:
-
[Javaの場合は確認
配列に値が含まれています]
Javaで配列をコピーする方法
配列の最初の要素]**
https://www.baeldung.com/java-array-min-max
Javaによる配列]**
https://www.baeldung.com/java-array-sum-average
[Find Sum and Average
Java]**
結合および分割配列
Javaのコレクション]**
https://www.baeldung.com/java-combine-collections
[Combining Different
Javaにおけるコレクションの型]**
すべて検索
与えられた合計を合計する配列内の数字のペア]**
Javaでのソート
Javaの電卓]**
InsertionソートインJava
16.結論
配列はJavaの中心的な機能の1つなので、配列がどのように機能するのかを理解し、それを使用してできることとできないことを知ることが非常に重要です。
このチュートリアルでは、一般的なシナリオで配列操作を適切に処理する方法を学びました。
いつものように、作業例の完全なソースコードはhttps://github.com/eugenp/tutorials/tree/master/core-java-arrays[私たちのGithubレポ]で利用可能です。