Java Language
リスト
サーチ…
前書き
リストは順序付けられた値の集合です。 Javaでは、リストはJava Collections Frameworkの一部です。リストは、実装java.util.List
延びインタフェース、 java.util.Collection
。
構文
- ls.add(E要素); //要素を追加する
- ls.remove(E要素); //要素を削除する
- for(E element:ls){} //各要素を繰り返します
- ls.toArray(新しい文字列[ls.length]); //ストリングのリストをストリングの配列に変換する
- ls.get(int index); //指定されたインデックスにある要素を返します。
- ls.set(int index、E element); //指定された位置に要素を置き換えます。
- ls.isEmpty(); //配列に要素がない場合はtrue、そうでない場合はfalseを返します。
- ls.indexOf(オブジェクトo); //指定された要素oの最初の位置のインデックスを返します。存在しない場合は-1を返します。
- ls.lastIndexOf(オブジェクトo); //指定された要素oの最後の位置のインデックスを返します。存在しない場合は-1を返します。
- ls.size(); //リスト内の要素の数を返します。
備考
リストは、順序付けられた値の集合を格納するオブジェクトです。 「オーダーされた」とは、値が特定の順序で格納されていることを意味します.1つは最初に、もう1つは2番目に続きます。個々の値は一般に「要素」と呼ばれます。 Javaのリストには、通常、次の機能があります。
- リストには0個以上の要素が含まれています。
- リストに重複した値が含まれている可能性があります。つまり、要素を複数回リストに挿入することができます。
- リストは要素を特定の順序で格納します。つまり、最初に要素が来る、次が来るなどを意味します。
- 各要素には、リスト内の位置を示すインデックスがあります 。最初の要素はインデックス0を持ち、次の要素はインデックス1を持ちます。
- リストは、リストの先頭、最後、または任意のインデックスに要素を挿入することを許可します。
- リストに特定の値が含まれているかどうかをテストするとは、通常、リスト内の各要素を調べることを意味します。これは、このチェックを実行する時間がリストのサイズに比例するO(n)であることを意味します。
末尾以外の点でリストに値を追加すると、次の要素がすべて「下に」または「右に」移動します。換言すれば、指数nの要素を追加するように、インデックスN + 1とする率nになるように使用される要素を移動させます。例えば:
List<String> list = new ArrayList<>();
list.add("world");
System.out.println(list.indexOf("world")); // Prints "0"
// Inserting a new value at index 0 moves "world" to index 1
list.add(0, "Hello");
System.out.println(list.indexOf("world")); // Prints "1"
System.out.println(list.indexOf("Hello")); // Prints "0"
ジェネリックリストのソート
Collections
クラスは、リストをソートする2つの標準的な静的メソッドを提供します。
-
sort(List<T> list)
は、T extends Comparable<? super T>
どこにあるT extends Comparable<? super T>
を示すリストに適用可能T extends Comparable<? super T>
、 - 任意の型のリストに適用可能
sort(List<T> list, Comparator<? super T> c)
前者を適用するには、ソートされるリスト要素のクラスを修正する必要がありますが、これは必ずしも可能ではありません。また、デフォルトソートや、別の状況でのソートオーダー、ソートなどのタスクが必要な場合がありますが、望ましくない場合もあります。
次のクラスのインスタンスであるオブジェクトをソートするタスクがあるとします。
public class User {
public final Long id;
public final String username;
public User(Long id, String username) {
this.id = id;
this.username = username;
}
@Override
public String toString() {
return String.format("%s:%d", username, id);
}
}
Collections.sort(List<User> list)
をUser
するには、 Comparable
インターフェースを実装するためにUser
クラスを変更する必要があります。例えば
public class User implements Comparable<User> {
public final Long id;
public final String username;
public User(Long id, String username) {
this.id = id;
this.username = username;
}
@Override
public String toString() {
return String.format("%s:%d", username, id);
}
@Override
/** The natural ordering for 'User' objects is by the 'id' field. */
public int compareTo(User o) {
return id.compareTo(o.id);
}
}
(別名: String
、 Long
、 Integer
などの多くの標準JavaクラスはComparable
インターフェイスを実装しているため、これらの要素のリストがデフォルトでソート可能になり、他のクラスのcompare
またはcompareTo
実装が簡単になります)
上記の変更により、クラスの自然順序付けに基づいてUser
オブジェクトのリストを簡単にソートできます。 (この場合、 id
値に基づいて順序付けすることが定義されています)。例えば:
List<User> users = Lists.newArrayList(
new User(33L, "A"),
new User(25L, "B"),
new User(28L, ""));
Collections.sort(users);
System.out.print(users);
// [B:25, C:28, A:33]
しかし、 User
オブジェクトをid
ではなくname
でソートしたいとします。あるいは、 Comparable
実装Comparable
ためにクラスを変更できなかったとします。
これは、 Comparator
引数を使用したsort
メソッドが便利な場所です。
Collections.sort(users, new Comparator<User>() {
@Override
/* Order two 'User' objects based on their names. */
public int compare(User left, User right) {
return left.username.compareTo(right.username);
}
});
System.out.print(users);
// [A:33, B:25, C:28]
Java 8では、匿名クラスの代わりにラムダを使用できます。後者は1ライナーに減少します:
Collections.sort(users, (l, r) -> l.username.compareTo(r.username));
さらに、Java 8では、 List
インターフェースにデフォルトのsort
メソッドが追加されているため、ソートがさらに簡単になります。
users.sort((l, r) -> l.username.compareTo(r.username))
リストの作成
あなたのリストにタイプを与える
リストを作成するには、型(クラスなど、 String
)が必要です。これはあなたのList
のタイプです。 List
は、指定されたタイプのオブジェクトのみが格納されます。例えば:
List<String> strings;
"string1"
、 "hello world!"
格納することができます"hello world!"
、 "goodbye"
などですが、 9.2
は保存できません:
List<Double> doubles;
9.2
保存できますが、 "hello world!"
は保存できません"hello world!"
。
あなたのリストを初期化する
上記のリストに何かを追加しようとすると、NullPointerExceptionが発生します。これは、 strings
とdoubles
両方がnullに等しいためです。
リストを初期化するには、次の2つの方法があります。
オプション1:Listを実装するクラスを使用する
List
はインタフェースであり、コンストラクタを持たず、むしろクラスがオーバーライドする必要があるメソッドを意味します。 ArrayList
は最も一般的に使用されるList
ArrayList
が、 LinkedList
も一般的です。そこで、次のようにリストを初期化します。
List<String> strings = new ArrayList<String>();
または
List<String> strings = new LinkedList<String>();
Java SE 7からは、 ダイヤモンド演算子を使用できます。
List<String> strings = new ArrayList<>();
または
List<String> strings = new LinkedList<>();
オプション2:Collectionsクラスを使用する
Collections
クラスは、 List
変数なしでList
を作成する2つの便利なメソッドを提供します:
-
emptyList()
:空のリストを返します。 -
singletonList(T)
:singletonList(T)
型のリストを作成し、指定された要素を追加します。
既存のList
を使用してデータを入力する方法
-
addAll(L, T...)
:指定されたすべての要素を、最初のパラメータとして渡されたリストに追加します。
例:
import java.util.List; import java.util.Collections; List<Integer> l = Collections.emptyList(); List<Integer> l1 = Collections.singletonList(42); Collections.addAll(l1, 1, 2, 3);
位置情報アクセス操作
List APIには、位置アクセス操作のための8つのメソッドがあります。
-
add(T type)
-
add(int index, T type)
-
remove(Object o)
-
remove(int index)
-
get(int index)
-
set(int index, E element)
-
int indexOf(Object o)
-
int lastIndexOf(Object o)
だから、リストがあれば:
List<String> strings = new ArrayList<String>();
文字列「Hello world!」を追加したかったのです。と "さようなら世界!"それには、私たちはそれをそうするでしょう:
strings.add("Hello world!");
strings.add("Goodbye world!");
私たちのリストには2つの要素が含まれています。ここで「プログラムの開始!」を追加したいとします。リストの前に私たちはこれを次のようにします:
strings.add(0, "Program starting!");
注:最初の要素は0です。
さて、「さようなら世界!私たちはこれを次のようにすることができます:
strings.remove("Goodbye world!");
そして、最初の行を削除したい場合(この場合は「プログラム開始!」となります)、次のようにして実行できます。
strings.remove(0);
注意:
リスト要素を追加および削除するとリストが変更され、リストが同時に反復されている場合、
ConcurrentModificationException
が発生する可能性があります。リストクラス、使用されるメソッド、およびリストの先頭、末尾、または中央に要素を追加/削除するかどうかによって、要素の追加と削除は
O(1)
またはO(N)
になります。
指定された位置でリストの要素を取得するには、 E get(int index);
List APIのメソッド例えば:
strings.get(0);
リストの最初の要素を返します。
set(int index, E element);
を使用して、指定された位置にある任意の要素を置き換えることができset(int index, E element);
。例えば:
strings.set(0,"This is a replacement");
これにより、リストの最初の要素として文字列 "This is a replacement"が設定されます。
注:setメソッドは、位置0の要素を上書きします。位置0に新しいStringを追加せず、古いものを位置1にプッシュします。
int indexOf(Object o);
引数として渡されたオブジェクトの最初の出現位置を返します。リストにオブジェクトがない場合、-1の値が返されます。前の例の続きで:
strings.indexOf("This is a replacement")
リストの0番目の位置に "これは置換文字列"を設定しているので、0が返されることが期待されます。リストに複数のオカレンスがある場合int indexOf(Object o);
前述のように最初のオカレンスのインデックスが返されます。 int lastIndexOf(Object o)
を呼び出すことで、リスト内の最後のオカレンスのインデックスを取得できます。したがって、別の「これは置き換え」を追加した場合:
strings.add("This is a replacement");
strings.lastIndexOf("This is a replacement");
今回は1が返され、0は返されません。
リスト内の要素を反復する
この例では、「hello」、「how」、「are」、「you?」の4つの要素を含むString型のリストがあります。
各要素を反復処理する最良の方法は、for-eachループを使用することです。
public void printEachElement(List<String> list){
for(String s : list){
System.out.println(s);
}
}
どちらが印刷されます:
hello,
how
are
you?
それらをすべて同じ行に印刷するには、StringBuilderを使用できます。
public void printAsLine(List<String> list){
StringBuilder builder = new StringBuilder();
for(String s : list){
builder.append(s);
}
System.out.println(builder.toString());
}
印刷されます:
hello, how are you?
あるいは、要素のインデックス付け( ArrayListのi番目のインデックスにある要素へのアクセスを参照)を使用してリストを反復することができます。警告:この方法は、リンクされたリストでは効率的ではありません。
リストAに存在するリストBから要素を削除する
あなたは2つのリストAとBを持っている、とあなたはBからあなたは、この場合に方法を持っているすべての要素を削除したいですと仮定します
List.removeAll(Collection c);
#例:
public static void main(String[] args) {
List<Integer> numbersA = new ArrayList<>();
List<Integer> numbersB = new ArrayList<>();
numbersA.addAll(Arrays.asList(new Integer[] { 1, 3, 4, 7, 5, 2 }));
numbersB.addAll(Arrays.asList(new Integer[] { 13, 32, 533, 3, 4, 2 }));
System.out.println("A: " + numbersA);
System.out.println("B: " + numbersB);
numbersB.removeAll(numbersA);
System.out.println("B cleared: " + numbersB);
}
これは印刷されます
A:[1、3、4、7、5、2]
B:[13,32,533,3,4,2]
Bをクリア:[13,32,533]
2つのリスト間の共通要素の検索
AとBの2つのリストがあり、両方のリストに存在する要素を見つける必要があるとします。
List.retainAll()
メソッドを呼び出すだけでそれを行うことができます。
例:
public static void main(String[] args) {
List<Integer> numbersA = new ArrayList<>();
List<Integer> numbersB = new ArrayList<>();
numbersA.addAll(Arrays.asList(new Integer[] { 1, 3, 4, 7, 5, 2 }));
numbersB.addAll(Arrays.asList(new Integer[] { 13, 32, 533, 3, 4, 2 }));
System.out.println("A: " + numbersA);
System.out.println("B: " + numbersB);
List<Integer> numbersC = new ArrayList<>();
numbersC.addAll(numbersA);
numbersC.retainAll(numbersB);
System.out.println("List A : " + numbersA);
System.out.println("List B : " + numbersB);
System.out.println("Common elements between A and B: " + numbersC);
}
整数のリストを文字列のリストに変換する
List<Integer> nums = Arrays.asList(1, 2, 3);
List<String> strings = nums.stream()
.map(Object::toString)
.collect(Collectors.toList());
あれは:
- リストからストリームを作成する
-
Object::toString
を使用して各要素をマップする -
Collectors.toList()
を使用してString
値をList
収集する
ArrayListからの要素の作成、追加、および削除
ArrayList
は、Javaの組み込みデータ構造の1つArrayList
。これは、要素(オブジェクト)を格納するための動的配列(最初に宣言する必要のないデータ構造体のサイズ)です。
AbstractList
クラスを拡張し、 List
インタフェースを実装します。 ArrayList
は、挿入順序を維持する重複要素を含めることができます。 ArrayList
クラスは同期していないので、 ArrayList
を使用して並行処理を行う場合は注意が必要ArrayList
。 ArrayList
はインデックスベースで動作するため、ランダムアクセスが可能ArrayList
。要素が配列リストから削除されたときに頻繁に発生するシフトのため、 ArrayList
操作が遅くなります。
ArrayList
は、次のように作成できます。
List<T> myArrayList = new ArrayList<>();
T
( Generics )は、 ArrayList
内に格納される型ArrayList
。
ArrayList
の型は任意のObjectにすることができます。型はプリミティブ型ではありません(代わりにラッパークラスを使用してください)。
ArrayList
に要素を追加するには、 add()
メソッドを使用します。
myArrayList.add(element);
または特定のインデックスにアイテムを追加するには:
myArrayList.add(index, element); //index of the element should be an int (starting from 0)
ArrayList
から項目を削除するには、 remove()
メソッドを使用します。
myArrayList.remove(element);
または特定のインデックスからアイテムを削除するには:
myArrayList.remove(index); //index of the element should be an int (starting from 0)
List要素のインプレース置換
この例では、置き換え要素が置き換えられる要素と同じ位置にあることを保証しながらList
要素を置き換える方法について説明します。
これは、次の方法を使用して実行できます。
- set(int index、T type)
- int indexOf(Tタイプ)
要素 "Program starting!"、 "Hello world!"を含むArrayList
を考えてみましょう。と "さようなら世界!"
List<String> strings = new ArrayList<String>();
strings.add("Program starting!");
strings.add("Hello world!");
strings.add("Goodbye world!");
置き換えたい要素のインデックスがわかっている場合は、単にset
を次のように使用します。
strings.set(1, "Hi world");
インデックスがわからない場合は、最初に検索することができます。例えば:
int pos = strings.indexOf("Goodbye world!");
if (pos >= 0) {
strings.set(pos, "Goodbye cruel world!");
}
ノート:
-
set
操作ではConcurrentModificationException
は発生しません。 -
set
操作はArrayList
では高速(O(1)
)、LinkedList
では低速(O(N)
)です。 -
ArrayList
またはLinkedList
のindexOf
検索が遅い(O(N)
)。
リストを変更不可能にする
Collectionsクラスは、リストを変更不可能にする方法を提供します。
List<String> ls = new ArrayList<String>();
List<String> unmodifiableList = Collections.unmodifiableList(ls);
1つのアイテムを持つ変更不可能なリストが必要な場合は、次のものを使用できます。
List<String> unmodifiableList = Collections.singletonList("Only string in the list");
リスト内のオブジェクトを移動する
Collectionsクラスでは、さまざまなメソッド(リストはls)を使用して、リスト内のオブジェクトを移動することができます。
リストを逆転する:
Collections.reverse(ls);
リスト内の要素の回転位置
rotateメソッドには整数の引数が必要です。これは、行に沿ってそれを移動するためにいくつのスポットです。その一例を以下に示します。
List<String> ls = new ArrayList<String>();
ls.add(" how");
ls.add(" are");
ls.add(" you?");
ls.add("hello,");
Collections.rotate(ls, 1);
for(String line : ls) System.out.print(line);
System.out.println();
これは "こんにちは、元気?"
リスト内の要素をシャッフルする
上記の同じリストを使用して、リスト内の要素をシャッフルすることができます:
Collections.shuffle(ls);
また、java.util.Randomオブジェクトにオブジェクトをランダムに配置するために使用することもできます。
Random random = new Random(12);
Collections.shuffle(ls, random);
リストを実装するクラス - 長所と短所
List
インタフェースは、異なるクラスによって実装されています。それぞれには、さまざまな戦略でそれを実装し、さまざまな賛否両論を提供する独自の方法があります。
リストを実装するクラス
java.util.List
インタフェースを実装するJava SE 8のすべてのpublic
クラスです。
- 抽象クラス:
- AbstractList
- AbstractSequentialList
- 具体的なクラス:
- 配列リスト
- AttributeList
- CopyOnWriteArrayList
- LinkedList
- ロールリスト
- RoleUnresolvedList
- スタック
- ベクター
時間の複雑さの観点から各実装の長所と短所
配列リスト
public class ArrayList<E>
extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, Serializable
ArrayListは、Listインタフェースのサイズ変更可能な配列実装です。配列にリストを格納するArrayListは、配列のサイズを操作するためのメソッド( Listインタフェースを実装するメソッドに加えて)を提供します。
IntegerのArrayListをサイズ100で初期化します。
List<Integer> myList = new ArrayList<Integer>(100); // Constructs an empty list with the specified initial capacity.
- PROS:
size、isEmpty、 get 、 set 、iterator、およびlistIteratorオペレーションは一定の時間内に実行されます。したがって、リストの各要素を取得して設定するのに同じ時間コストが必要です。
int e1 = myList.get(0); // \
int e2 = myList.get(10); // | => All the same constant cost => O(1)
myList.set(2,10); // /
- 条件:
アレイのサイズを超えて要素を追加する配列(静的構造)で実装されていると、すべての配列に対して新しい割り当てを行う必要があるため、大きなコストがかかります。ただし、 ドキュメントから:
加算演算は償却された一定時間で実行されます。つまり、n個の要素を追加するにはO(n)時間が必要です
要素を削除するには、O(n)時間が必要です。
AttributeList
来る時に
CopyOnWriteArrayList
来る時に
LinkedList
public class LinkedList<E>
extends AbstractSequentialList<E>
implements List<E>, Deque<E>, Cloneable, Serializable
LinkedListは、 二重リンクされたリストによって、ノードと呼ばれる連続してリンクされたレコードのセットで構成されるリンクされたデータ構造によって実装されます。
整数のLinkedListを初期化する
List<Integer> myList = new LinkedList<Integer>(); // Constructs an empty list.
- PROS:
リストの先頭または末尾に要素を追加または削除するときには、一定の時間があります。
myList.add(10); // \
myList.add(0,2); // | => constant time => O(1)
myList.remove(); // /
- 締め切り: ドキュメントから:
リストにインデックスを付けるオペレーションは、指定されたインデックスに近いほうからリストの先頭または末尾を走査します。
以下のような操作:
myList.get(10); // \
myList.add(11,25); // | => worst case done in O(n/2)
myList.set(15,35); // /
ロールリスト
来る時に
RoleUnresolvedList
来る時に
スタック
来る時に
ベクター
来る時に