JavaでArrayListからArrayListをスライスするにはどうすればよいですか?


80

ArrayListJavaでの配列スライスを取得するにはどうすればよいですか?具体的には、次のようなことをしたいと思います。

ArrayList<Integer> inputA = input.subList(0, input.size()/2);
// where 'input' is a prepouplated ArrayList<Integer>

したがって、これが機能することを期待していましたが、JavaはList-を返すため、互換性がありません。そして、私がそれをキャストしようとすると、Javaは私を許可しません。私は必要ですArrayList-私は何ができますか?


4
なぜあなたは使用を主張するのArrayListですか?インターフェースがどのように機能するかを少し理解していないかもしれません。なぜならListArrayList「互換性がない」わけではなく、ArrayList実装されてListおり、Listおそらく必要なすべてのメソッドが含まれているからです。
Bombe

2
私はArrayListの使用を主張します。これは、厳密なメソッドのプロトタイプを使用したインタビューの質問だからです。subListはList型を返すことになっているのに、返されたListをArrayListにキャストできないため、私は明らかに理解が不足しています。だからあなたは私に男を教えてください
BT

4
ArrayListを受け入れるメソッドを呼び出す必要があるため、が必要になる可能性は十分にありArrayListます。おそらく、そのような方法は設計が不十分であり、List代わりに受け入れる必要がありますが、そのような状況は、面接の質問だけでなく、他の人が書いたコードでも発生する可能性があります。同僚や図書館は必ずしも完璧ではありません。
重力

回答:


124

Javaでは、APIで具象クラスではなくインターフェース型を使用することをお勧めします。

あなたの問題は、あなたがArrayList本当に使うべき場所で(おそらく多くの場所で)使っているということListです。その結果、リストがであるという不必要な制約を伴う問題が発生しましたArrayList

コードは次のようになります。

List input = new ArrayList(...);

public void doSomething(List input) {
   List inputA = input.subList(0, input.size()/2);
   ...
}

this.doSomething(input);

問題に対して提案された「解決策」は次のとおりです。

new ArrayList(input.subList(0, input.size()/2))

これは、サブリストのコピーを作成することで機能します。通常の意味でのスライスではありません。さらに、サブリストが大きい場合、コピーの作成にはコストがかかります。


変更できないAPIに制約されている場合は、inputAとして宣言する必要があります。ArrayListArrayListsubListメソッドがのサブクラスを返すカスタムサブクラスを実装できる可能性がありArrayListます。しかしながら:

  1. 設計、実装、テストするのは大変な作業です。
  2. これで、コードベースに重要な新しいクラスが追加されました。おそらく、クラスの文書化されていない側面(したがって「変更される可能性がある」)の側面に依存していArrayListます。
  3. 作成しているコードベースの関連する場所を変更する必要があります ArrayList代わりに、サブクラスのインスタンスを作成するために、インスタンスを作成ます。

「アレイをコピーする」ソリューションはより実用的です...これらは真のスライスではないことを念頭に置いてください。


6
実際、subListはコピーを作成しません。それは、元のリスト(にビューを返しdocs.oracle.com/javase/6/docs/api/java/util/...
マット

3
実際に@Matthew、私は彼がこれを行うOPの自己回答に言及しています:new ArrayList(input.subList(0, input.size()/2))
Stephen C

1
このフレーズの+1:Javaでは、APIで具象クラスではなくインターフェース型を使用することをお勧めします。
Ilonpilaaja

6

ArrayListから削除する必要のある要素のstartIndexとendIndexを知っている場合は、方法を見つけました。

させるal元のArrayListこととstartIndexendIndexそれぞれのアレイから削除された開始及び終了インデックスです。

al.subList(startIndex, endIndex + 1).clear();

6

既存のメソッドがない場合は、0からまで繰り返すことができると思います input.size()/2て、連続する各要素を取得、それを新しいArrayListに追加。

編集:実際には、そのリストを取得し、それを使用して、ArrayListコンストラクターの1つを使用して新しいArrayListをインスタンス化できると思います。


2
それはまさに私がしたことです(私があなたの編集を読む前に私の答えを投稿しました)。ありがとう:)
BT

しかし、それはリストをコピーして新しいArrayListを作成します。
Joren 2009

2
@ BT-記録のために、それは「スライス」という用語がこの文脈で通常意味するものではありません。
スティーブンC

2

この投稿はとても古いですが。誰かがこれを探している場合に備えて..

Guavaは、リストを指定されたサイズのサブリストに分割するのを容易にします

List<Integer> intList = Lists.newArrayList(1, 2, 3, 4, 5, 6, 7, 8);
    List<List<Integer>> subSets = Lists.partition(intList, 3);

グアバリストのドキュメントへのクイックリンク:google.github.io/guava/releases/19.0/api/docs/com/google/common/...
AryanJ-NYC

-4

これが私がそれを解決した方法です。サブリストが元のリストの要素への直接参照であることを忘れたので、それが機能しない理由は理にかなっています。

ArrayList<Integer> inputA = new ArrayList<Integer>(input.subList(0, input.size()/2));
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.