Làm cách nào để tách ArrayList ra khỏi ArrayList trong Java?


80

Làm cách nào để lấy một lát mảng của một ArrayListtrong Java? Cụ thể là tôi muốn làm điều gì đó như sau:

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

Vì vậy, tôi mong đợi điều này sẽ hoạt động, nhưng Java trả về một List- vì vậy nó không tương thích. Và khi tôi cố gắng truyền nó, Java sẽ không cho phép tôi. Tôi cần một ArrayList- tôi có thể làm gì?


4
Tại sao bạn nhấn mạnh vào việc sử dụng một ArrayList? Tôi nghĩ rằng bạn có thể thiếu một chút hiểu biết về cách thức hoạt động của các giao diện bởi vì ListArrayListkhông phải là "không tương thích" - các ArrayListcài đặt ListListcó thể chứa tất cả các phương pháp cần thiết mà bạn cần.
Bombe 26/09/09

2
Tôi nhấn mạnh vào việc sử dụng ArrayList vì nó là một câu hỏi tương tác với một nguyên mẫu phương pháp cứng nhắc. Tôi rõ ràng là thiếu hiểu biết, bởi vì subList được cho là trả về một loại Danh sách, nhưng tôi không thể chuyển Danh sách được trả về sang ArrayList. Vì vậy, bạn nói với tôi bạn đàn ông ..
BT

4
Hoàn toàn có thể là anh ta cần một ArrayListvì sau đó anh ta cần gọi một phương thức với nó chấp nhận một ArrayList. Có thể cho rằng một phương pháp như vậy được thiết kế kém và nên được chấp nhận Listthay thế, nhưng những tình huống như vậy có thể phát sinh không chỉ trong các câu hỏi phỏng vấn mà còn trong mã do người khác viết mà người ta không thể chỉ đi và thay đổi. Đồng nghiệp và thư viện không phải lúc nào cũng hoàn hảo.
Gravity

Câu trả lời:


124

Trong Java, bạn nên sử dụng các kiểu giao diện thay vì các lớp cụ thể trong API.

Vấn đề của bạn là bạn đang sử dụng ArrayList(có thể ở nhiều nơi), nơi bạn thực sự nên sử dụng List. Kết quả là bạn đã tạo ra các vấn đề cho chính mình với một ràng buộc không cần thiết mà danh sách là một ArrayList.

Đây là mã của bạn sẽ trông như thế nào:

List input = new ArrayList(...);

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

this.doSomething(input);

"Giải pháp" được đề xuất của bạn cho vấn đề là / là:

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

Điều đó hoạt động bằng cách tạo một bản sao của danh sách phụ. Nó không phải là một lát cắt theo nghĩa thông thường. Hơn nữa, nếu danh sách con lớn, thì việc sao chép sẽ rất tốn kém.


Nếu bạn bị ràng buộc bởi các API mà bạn không thể thay đổi , chẳng hạn như bạn phải khai báo inputAlà một ArrayList, bạn có thể triển khai một lớp con tùy chỉnh ArrayListtrong đó subListphương thức trả về một lớp con ArrayList. Tuy nhiên:

  1. Sẽ rất nhiều công việc để thiết kế, thực hiện và thử nghiệm.
  2. Bây giờ bạn đã thêm lớp mới quan trọng vào cơ sở mã của mình, có thể với các phụ thuộc vào các khía cạnh không có tài liệu (và do đó "có thể thay đổi") của ArrayListlớp.
  3. Bạn sẽ cần thay đổi các vị trí có liên quan trong cơ sở mã của mình, nơi bạn đang tạo các ArrayListphiên bản để tạo các phiên bản của lớp con thay thế.

Giải pháp "sao chép mảng" thực tế hơn ... lưu ý rằng đây không phải là những lát cắt đúng.


6
Trên thực tế, subList không tạo một bản sao; nó trả về một chế độ xem vào danh sách ban đầu ( docs.oracle.com/javase/6/docs/api/java/util/… )
Matt

3
Trên thực tế @Matthew, tôi đề cập đến tự câu trả lời của OP nơi ông thực hiện điều này:new ArrayList(input.subList(0, input.size()/2))
Stephen C

1
+1 cho cụm từ này: Trong Java, bạn nên sử dụng các kiểu giao diện thay vì các lớp cụ thể trong API.
Ilonpilaaja

6

Tôi đã tìm ra cách nếu bạn biết startIndex và endIndex của các phần tử cần xóa khỏi ArrayList

Hãy allà ArrayList ban đầu và startIndex, endIndexlà chỉ mục bắt đầu và kết thúc được xóa khỏi mảng tương ứng:

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

6

Nếu không có phương thức nào hiện có thì tôi đoán bạn có thể lặp lại từ 0 đến input.size()/2, lấy từng phần tử liên tiếp và thêm nó vào một ArrayList mới.

CHỈNH SỬA : Trên thực tế, tôi nghĩ bạn có thể lấy Danh sách đó và sử dụng nó để khởi tạo một ArrayList mới bằng cách sử dụng một trong các hàm tạo ArrayList .


2
Đó là chính xác những gì tôi đã làm (đã đăng câu trả lời của tôi trước khi tôi đọc bản chỉnh sửa của bạn). Cảm ơn:)
BT

Nhưng điều đó sao chép Danh sách để tạo một ArrayList mới.
Joren

2
@BT - Đối với bản ghi, đó không phải là điều mà thuật ngữ "lát cắt" thường có nghĩa trong ngữ cảnh này.
Stephen C

2

Mặc dù bài đăng này rất cũ. Trong trường hợp nếu ai đó đang tìm kiếm điều này ..

Ổi tạo điều kiện thuận lợi cho việc phân vùng Danh sách thành các danh sách con có kích thước xác định

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

Liên kết nhanh đến tài liệu Danh sách Ổi: google.github.io/guava/releases/19.0/api/docs/com/google/common/…
AryanJ-NYC

-4

Đây là cách tôi giải quyết nó. Tôi quên rằng danh sách phụ là một tham chiếu trực tiếp đến các phần tử trong danh sách ban đầu, vì vậy có lý do tại sao nó không hoạt động.

ArrayList<Integer> inputA = new ArrayList<Integer>(input.subList(0, input.size()/2));
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.