Làm cách nào để tham gia hai danh sách trong Java?


749

Điều kiện: không sửa đổi danh sách ban đầu; Chỉ JDK, không có thư viện bên ngoài. Điểm thưởng cho phiên bản một lớp hoặc JDK 1.3.

Có cách nào đơn giản hơn:

List<String> newList = new ArrayList<String>();
newList.addAll(listOne);
newList.addAll(listTwo);

5
Nếu bạn đang làm điều này chỉ với mục đích lặp lại, hãy xem một câu hỏi khác - có các giải pháp google guava và java 8 stackoverflow.com/questions/3616662/
Kẻ

Giải pháp Java 8 với phương thức tiện ích: stackoverflow.com/a/37386846/1216775
akhil_mittal

Sau khi đọc một số câu trả lời, tôi xin lỗi tôi đã hỏi.
Anthony Rutledge

Câu trả lời:


591

Trong Java 8:

List<String> newList = Stream.concat(listOne.stream(), listTwo.stream())
                             .collect(Collectors.toList());

82
Gawd, đó là một điều trong Java 8? Về mặt kỹ thuật bạn thắng tôi đoán, nhưng đó là một chặng đường dài :-)
Robert Atkins

4
Đối với người đọc thông thường, đây là một giải pháp ngắn hơn bằng cách sử dụng Java _ Streams: stackoverflow.com/a/34090554/363573
Stephan

7
Nó xấu xí nhưng ít nhất là thông thạo và có thể được sử dụng mà không cần lambdas nhiều dòng. Tôi thực sự muốn có một add ALL lưu loát trả về danh sách được kết nối.
Usman Ismail

6
Tôi đoán rằng đáng chú ý là thực sự dễ dàng để có được một danh sách riêng biệt từ điều này, như vậy:List<String> newList = Stream.concat(listOne.stream(), listTwo.stream()).distinct().collect(Collectors.toList());
Roger

1
Thay thế cho concat: dòng suốiStream.of(listOne, listTwo).flatMap(Collection::stream).collect(Collectors.toList())
Peter Walser

569

Ngoài đỉnh đầu, tôi có thể rút ngắn nó bằng một dòng:

List<String> newList = new ArrayList<String>(listOne);
newList.addAll(listTwo);

156
Trong khi bạn đúng về mặt kỹ thuật, bạn đã rút ngắn nó bằng một dòng, sự bất cân xứng của điều này làm tôi khó chịu. Đủ để tôi hạnh phúc hơn khi "dành" thêm dòng.
Robert Atkins

13
Ở đây không có vấn đề gì khi mảng liên kết của newList sẽ được khởi tạo theo kích thước của listOne và sau đó phải mở rộng khi thêm tất cả các mục từ listTwo? Sẽ tốt hơn nếu lấy kích thước của mỗi danh sách và sử dụng nó để kích thước mảng mới?
Eric

2
Đây là giải pháp tốt nhất cho tôi. Tôi đã làm một so sánh về hiệu suất của các giải pháp khác nhau mà người chiến thắng này đã đưa ra, cùng với việc tạo ra danh sách trống và sau đó addAll()là cả hai. Tôi đã thử tất cả những đề xuất không sao chép danh sách và kết quả là chúng có rất nhiều chi phí mà chúng tôi không cần đến lúc này.
manuelvigarcia

đẹp nhưng bạn thậm chí có thể làm cho nó ngắn hơn: List list = new ArrayList <> (list1) .add ALL (list2);
vận tốc

1
@velocity: không, điều đó sẽ không hiệu quả. addAll(Collection)trả về a boolean.
Stijn Van Bael

306

Bạn có thể sử dụng thư viện bộ sưu tập chung của Apache :

List<String> newList = ListUtils.union(list1, list2);

52
Đẹp, nhưng đòi hỏi apache commons. Anh ấy đã chỉ định 'không có thư viện bên ngoài'
Quantum7

101
@ Quantum7, vẫn hữu ích cho người khác;) Ngoài ra, apache có phải là một thư viện bên ngoài không? Tôi không bắt đầu bất cứ điều gì mà không có nó!
chào

28
@Platinum Không, theo tài liệu ListUtils.union hoàn toàn tương đương với mã của OP. Nhưng có lẽ việc sử dụng thao tác SET ("Liên minh") trong ngữ cảnh danh sách là sai lầm. Tôi có thể thấy làm thế nào bạn có thể mong đợi điều này để loại bỏ trùng lặp hoặc một cái gì đó, nhưng có vẻ như phương pháp không làm điều đó.
Quantum7

24
Tránh các bộ sưu tập Apache Commons. Nó không an toàn, không có thuốc generic. Tuyệt vời nếu bạn sử dụng Java 1.4, nhưng đối với Java 5 trở lên, tôi thích Google Guava hơn.
Michael Piefel

11
@MichaelPiefel Bộ sưu tập Apache Commons 4 mới nhất là loại an toàn. Với tham chiếu phương thức Java 8, loại tiện ích tĩnh này trở nên rất quan trọng.
mingfai

93

Một trong những yêu cầu của bạn là giữ nguyên danh sách gốc. Nếu bạn tạo một danh sách mới và sử dụng addAll(), bạn đang nhân đôi số lượng tài liệu tham khảo cho các đối tượng trong danh sách của mình một cách hiệu quả. Điều này có thể dẫn đến các vấn đề về bộ nhớ nếu danh sách của bạn rất lớn.

Nếu bạn không cần sửa đổi kết quả được nối, bạn có thể tránh điều này bằng cách sử dụng triển khai danh sách tùy chỉnh. Lớp triển khai tùy chỉnh có nhiều hơn một dòng, rõ ràng ... nhưng sử dụng nó thì ngắn và ngọt ngào.

CompositeUnmodifiableList.java:

public class CompositeUnmodifiableList<E> extends AbstractList<E> {

    private final List<E> list1;
    private final List<E> list2;

    public CompositeUnmodifiableList(List<E> list1, List<E> list2) {
        this.list1 = list1;
        this.list2 = list2;
    }

    @Override
    public E get(int index) {
        if (index < list1.size()) {
            return list1.get(index);
        }
        return list2.get(index-list1.size());
    }

    @Override
    public int size() {
        return list1.size() + list2.size();
    }
}

Sử dụng:

List<String> newList = new CompositeUnmodifiableList<String>(listOne,listTwo);

15
Đây là câu trả lời thực sự cho câu hỏi này.
Wouter Lievens

9
Đây là một giải pháp khả thi, nhưng lưu ý rằng nếu các đối tượng danh sách cơ bản thay đổi (list1, list2), nội dung của danh sách này sẽ thay đổi. Bạn có thể không thể sửa đổi một thể hiện của chính CompositeUnmodifiableList nhưng nếu bạn có thể có được một tham chiếu đến các danh sách ban đầu, thì bạn có thể. Ngoài ra, đối với những người không quen thuộc: công cụ sửa đổi cuối cùng chỉ ảnh hưởng đến tham chiếu đến chính đối tượng danh sách không thể thay đổi nhưng nội dung của danh sách vẫn có thể thay đổi!
jwj

3
@jwj tất cả các điểm rất tốt, cảm ơn bạn. Tên lớp có lẽ xứng đáng một số lời giải thích. Tôi thấy lớp này đang làm một cái gì đó rất giống với Collections.unmodifiableList()phương thức, nó bao bọc một danh sách để làm cho nó không thể thay đổi. CompositeUnmodifiableListthực hiện điều tương tự, ngoại trừ nó bao bọc hai danh sách và cung cấp một khung nhìn được nối. Tất cả những điểm bạn đưa ra CompositeUnmodifiableListcũng đúng Collections.unmodifiableList().
Kevin K

2
Nhà xây dựng có thể mấtList<? extends E>
Patrick Parker

84

Có lẽ không đơn giản, nhưng hấp dẫn và xấu xí:

List<String> newList = new ArrayList<String>() { { addAll(listOne); addAll(listTwo); } };

Đừng sử dụng nó trong mã sản xuất ...;)


44
Xấu xí và xấu xa, gần như bất kỳ việc sử dụng khởi tạo cú đúp nào. Tuy nhiên, nó ngắn hơn;)
Jorn

4
@MarnixKlooster: Eclipse biết rằng bạn không nên sử dụng nó và khiến nó khó chịu khi sử dụng ;-)
Joachim Sauer

20
Mặc dù nó chỉ là một dòng, nhưng tôi không coi đây là "một lớp".
bắn tung tóe

11
Tại sao mọi người ghét công cụ khởi tạo khối ẩn danh
NimChimpsky

18
@NimChimpsky Tôi nghĩ rằng phần lớn là vì nó không chỉ là trình khởi tạo khối ẩn danh, mà thực sự bạn đang tạo một lớp con ẩn danh của ArrayList. Điều đó đang được nói, nếu bạn tin tưởng vào kết quả của câu hỏi Khởi tạo cú đúp này , có vẻ như việc ghét DBI chủ yếu là vấn đề về hương vị phong cách và tối ưu hóa vi mô. Theo như tôi có thể nói, không có hình phạt chính nào cho việc đó. Nhược điểm lén lút sẽ là nếu bạn từng cố so sánh lớp của nó vì nó sẽ không phải là ArrayList.
Patrick

75

Một lớp lót Java 8 khác:

List<String> newList = Stream.of(listOne, listTwo)
                            .flatMap(Collection::stream)
                            .collect(Collectors.toList());

Như một phần thưởng, vì Stream.of()là từ khóa , bạn có thể ghép bao nhiêu danh sách tùy thích.

List<String> newList = Stream.of(listOne, listTwo, listThree)
                            .flatMap(Collection::stream)
                            .collect(Collectors.toList());

35
x -> x.stream()có thể được thay thế bằng Collection::stream.
Martin

10
... Hoặc thậm chí với List::stream.
MC Hoàng đế

73

Không đơn giản, nhưng không thay đổi kích thước trên đầu:

List<String> newList = new ArrayList<>(listOne.size() + listTwo.size());
newList.addAll(listOne);
newList.addAll(listTwo);

55

Tìm thấy câu hỏi này để tìm cách kết hợp số lượng danh sách tùy ý, không bận tâm đến các thư viện bên ngoài. Vì vậy, có lẽ nó sẽ giúp người khác:

com.google.common.collect.Iterables#concat()

Hữu ích nếu bạn muốn áp dụng cùng logic cho một số bộ sưu tập khác nhau trong một cho ().


9
Ví dụ: Lists.newArrayList (Iterables.concat (list1, list2));
meilechh

bạn nên gọi com.google.common.collect.Iterators#concat(java.util.Iterator<? extends java.util.Iterator<? extends T>>)thay vì Iterables#concat(); bởi vì sau này vẫn sao chép các yếu tố vào liên kết tạm thời!
bob

45

Java 8 ( Stream.ofStream.concat)

Giải pháp đề xuất là cho ba danh sách mặc dù nó cũng có thể được áp dụng cho hai danh sách. Trong Java 8, chúng ta có thể sử dụng Stream.of hoặc Stream.concat như:

List<String> result1 = Stream.concat(Stream.concat(list1.stream(),list2.stream()),list3.stream()).collect(Collectors.toList());
List<String> result2 = Stream.of(list1,list2,list3).flatMap(Collection::stream).collect(Collectors.toList());

Stream.concatlấy hai luồng làm đầu vào và tạo ra một luồng kết hợp một cách lười biếng với các phần tử là tất cả các phần tử của luồng đầu tiên, theo sau là tất cả các phần tử của luồng thứ hai. Khi chúng tôi có ba danh sách, chúng tôi đã sử dụng phương thức này ( Stream.concat) hai lần.

Chúng ta cũng có thể viết một lớp tiện ích với một phương thức lấy bất kỳ số lượng danh sách (sử dụng varargs ) và trả về một danh sách được nối như:

public static <T> List<T> concatenateLists(List<T>... collections) {
        return Arrays.stream(collections).flatMap(Collection::stream).collect(Collectors.toList()); 
}

Sau đó, chúng ta có thể sử dụng phương pháp này như:

List<String> result3 = Utils.concatenateLists(list1,list2,list3);

Bạn có thể sẵn sàng nói List <String> result1 = Stream.concat (Stream.concat (list1.stream (), list2.stream ()), list3.stream ()). Coll (Collector.toList ()); trong toán tử đầu tiên của bạn. Hãy sửa chữa nó.
WebCome

44

Đây là một giải pháp java 8 sử dụng hai dòng:

List<Object> newList = new ArrayList<>();
Stream.of(list1, list2).forEach(newList::addAll);

Xin lưu ý rằng phương pháp này không nên được sử dụng nếu

  • nguồn gốc của newListkhông được biết và nó có thể đã được chia sẻ với các chủ đề khác
  • luồng sửa đổi newListlà luồng song song và quyền truy cập newListkhông được đồng bộ hóa hoặc luồng an toàn

do cân nhắc tác dụng phụ.

Cả hai điều kiện trên đều không áp dụng cho trường hợp tham gia hai danh sách trên, vì vậy điều này là an toàn.

Dựa trên câu trả lời này cho câu hỏi khác.


12
Nếu tôi không sai thì điều này thực sự không được khuyến khích - docs.oracle.com/javase/8/docs/api/java/util/stream/ chủ Xin vui lòng xem phần bên lề. > Nói chung, các tác dụng phụ trong các tham số hành vi đối với các hoạt động truyền phát, không được khuyến khích, vì chúng thường có thể dẫn đến việc vô tình vi phạm yêu cầu không trạng thái, cũng như các nguy cơ về an toàn luồng khác. Vì vậy, trong trường hợp này, tốt hơn là sử dụng Collector.toList ()
Anton Balaniuc

@AntonBalaniuc Câu hỏi là liệu điều này có thực sự là tác dụng phụ hay không. Tại thời điểm đó newListlà không thể quan sát bởi bất kỳ chủ đề khác. Nhưng bạn đã đúng rằng điều này có lẽ không nên được thực hiện nếu không biết giá trị newListđến từ đâu (ví dụ nếu newListđược truyền dưới dạng tham số.
SpaceTrucker

2
Tôi tò mò; Tại sao .forEach(newList::addAll);thay vì .collect(Collectors.toList());?
11684

4
@ 11684 vì người sưu tầm sẽ thu a List<List<Object>>. Những gì bạn có thể có trong đầu là một cái gì đó như thế này: stackoverflow.com/questions/189559/
Kẻ

@SpaceTrucker Rất tiếc, tôi đã bỏ qua điều đó. Cảm ơn đã làm sáng tỏ sự nhầm lẫn của tôi. Vâng, tôi nên đã nghĩ về flatMap.
11684

34

Điều này đơn giản và chỉ một dòng, nhưng sẽ thêm nội dung của listTwo vào listOne. Bạn có thực sự cần phải đưa nội dung vào danh sách thứ ba?

Collections.addAll(listOne, listTwo.toArray());

11
Không sửa đổi danh sách ban đầu là một trong những tiêu chí, nhưng điều này hữu ích để có ở đây làm ví dụ cho các tình huống không phải là một hạn chế.
Robert Atkins

1
Cảm ơn, hoặc thậm chí đơn giản hơn listOne.add ALL (listTwo)
Jay

27

Đơn giản hơn một chút:

List<String> newList = new ArrayList<String>(listOne);
newList.addAll(listTwo);

Điều này sẽ gây ra chuỗi trùng lặp? Có nghĩa là một Chuỗi tồn tại trong cả hai danh sách sẽ tồn tại hai lần trong danh sách kết quả?
Đặc vụKnopf

4
@Zainodis Có, có thể có bản sao. Các Listcấu trúc áp đặt không ràng buộc duy nhất. Bạn có thể loại bỏ các bản sao bằng cách thực hiện tương tự với các bộ. Set<String> newSet = new HashSet<>(setOne); newSet.addAll(setTwo);
Patrick

20

Một chút ngắn hơn sẽ là:

List<String> newList = new ArrayList<String>(listOne);
newList.addAll(listTwo);

17

Bạn có thể tạo phương thức tiện ích Java 8 chung của mình để nối bất kỳ số lượng danh sách nào .

@SafeVarargs
public static <T> List<T> concat(List<T>... lists) {
    return Stream.of(lists).flatMap(List::stream).collect(Collectors.toList());
}

13

Bạn có thể thực hiện một oneliner nếu danh sách mục tiêu được khai báo trước.

(newList = new ArrayList<String>(list1)).addAll(list2);


9

một giải pháp lót khác sử dụng Java8luồng, vì flatMapgiải pháp đã được đăng, đây là một giải pháp không cóflatMap

List<E> li = lol.stream().collect(ArrayList::new, List::addAll, List::addAll);

hoặc là

List<E> ints = Stream.of(list1, list2).collect(ArrayList::new, List::addAll, List::addAll);

    List<List<Integer>> lol = Arrays.asList(Arrays.asList(1, 2, 3), Arrays.asList(4, 5, 6));
    List<Integer> li = lol.stream().collect(ArrayList::new, List::addAll, List::addAll);
    System.out.println(lol);
    System.out.println(li);

đầu ra

[[1, 2, 3], [4, 5, 6]]
[1, 2, 3, 4, 5, 6]

1
Tôi sẽ nói thêm rằng giải pháp này có thể hiệu quả hơn so với giải pháp sử dụng flatMap, bởi vì các danh sách chỉ được lặp lại một lần khi chúng được thu thập
Stefan Haberl

7

Thông minh nhất theo quan điểm của tôi:

/**
 * @param smallLists
 * @return one big list containing all elements of the small ones, in the same order.
 */
public static <E> List<E> concatenate (final List<E> ... smallLists)
{
    final ArrayList<E> bigList = new ArrayList<E>();
    for (final List<E> list: smallLists)
    {
        bigList.addAll(list);
    }
    return bigList;
}

3
Đừng quên @SafeVarargs!
Radon Rosborough

6

Bạn có thể làm điều đó với một nhập tĩnh và một lớp trợ giúp

nb sự khái quát của lớp này có thể được cải thiện

public class Lists {

   private Lists() { } // can't be instantiated

   public static List<T> join(List<T>... lists) {
      List<T> result = new ArrayList<T>();
      for(List<T> list : lists) {
         result.addAll(list);
      }
      return results;
   }

}

Sau đó, bạn có thể làm những việc như

import static Lists.join;
List<T> result = join(list1, list2, list3, list4);

Làm thế nào là nhập tĩnh hoặc lớp người trợ giúp có liên quan?
shmosel

6

Phiên bản Java 8 có hỗ trợ tham gia bằng khóa đối tượng:

public List<SomeClass> mergeLists(final List<SomeClass> left, final List<SomeClass> right, String primaryKey) {
    final Map<Object, SomeClass> mergedList = new LinkedHashMap<>();

    Stream.concat(left.stream(), right.stream())
        .map(someObject -> new Pair<Object, SomeClass>(someObject.getSomeKey(), someObject))
        .forEach(pair-> mergedList.put(pair.getKey(), pair.getValue()));

    return new ArrayList<>(mergedList.values());
}

4
public static <T> List<T> merge(List<T>... args) {
    final List<T> result = new ArrayList<>();

    for (List<T> list : args) {
        result.addAll(list);
    }

    return result;
}

4

Sử dụng một lớp Helper.

Tôi đề nghị:

public static <E> Collection<E> addAll(Collection<E> dest, Collection<? extends E>... src) {
    for(Collection<? extends E> c : src) {
        dest.addAll(c);
    }

    return dest;
}

public static void main(String[] args) {
    System.out.println(addAll(new ArrayList<Object>(), Arrays.asList(1,2,3), Arrays.asList("a", "b", "c")));

    // does not compile
    // System.out.println(addAll(new ArrayList<Integer>(), Arrays.asList(1,2,3), Arrays.asList("a", "b", "c")));

    System.out.println(addAll(new ArrayList<Integer>(), Arrays.asList(1,2,3), Arrays.asList(4, 5, 6)));
}

3
public static <T> List<T> merge(@Nonnull final List<T>... list) {
    // calculate length first
    int mergedLength = 0;
    for (List<T> ts : list) {
      mergedLength += ts.size();
    }

    final List<T> mergedList = new ArrayList<>(mergedLength);

    for (List<T> ts : list) {
      mergedList.addAll(ts);
    }

    return mergedList;
  }

2

Chúng tôi có thể tham gia 2 danh sách bằng cách sử dụng java8 với 2 cách tiếp cận.

    List<String> list1 = Arrays.asList("S", "T");
    List<String> list2 = Arrays.asList("U", "V");

1) Sử dụng concat:

    List<String> collect2 = Stream.concat(list1.stream(), list2.stream()).collect(toList());
    System.out.println("collect2 = " + collect2); // collect2 = [S, T, U, V]

2) Sử dụng FlatMap:

    List<String> collect3 = Stream.of(list1, list2).flatMap(Collection::stream).collect(toList());
    System.out.println("collect3 = " + collect3); // collect3 = [S, T, U, V]

1
Khi trả lời một câu hỏi mười một tuổi với ba mươi câu trả lời khác, hãy chắc chắn chỉ ra những khía cạnh mới của câu hỏi mà bạn trả lời, và lưu ý nếu các kỹ thuật này sẽ hoạt động khi câu hỏi được hỏi, hoặc nếu chúng phụ thuộc vào các tính năng đã được được giới thiệu qua nhiều năm.
Jason Aller

2

Hầu hết các câu trả lời đề nghị sử dụng ArrayList.

List<String> newList = new LinkedList<>(listOne);
newList.addAll(listTwo);

Thích sử dụng LinkedList để hoạt động thêm hiệu quả.

ArrayList add là O (1) được khấu hao, nhưng trường hợp xấu nhất O (n) vì mảng phải được thay đổi kích thước và sao chép. Trong khi LinkedList add luôn không đổi O (1).

thêm thông tin https://stackoverflow.com/a/322742/311420


0

Tôi không khẳng định rằng nó đơn giản, nhưng bạn đã đề cập đến phần thưởng cho một lớp lót ;-)

Collection mergedList = Collections.list(new sun.misc.CompoundEnumeration(new Enumeration[] {
    new Vector(list1).elements(),
    new Vector(list2).elements(),
    ...
}))

Tại sao ai đó không bao giờ nên sử dụng chúng?
David

5
@David vì nó nhằm mục đích được sử dụng nội bộ trong JDK. Nếu bạn đã sử dụng mã đó trong mã của mình, mã của bạn có thể sẽ không chạy trên JDK / JRE không thuộc Sun.
Adrian Shum

@AdrianShum Có JDK / JRE nào khác ngoài Oracle không? Điều đó sẽ làm tôi ngạc nhiên. Ngay cả khi bị giới hạn ở chức năng API phổ biến nhất, việc xây dựng lại toàn bộ nội dung có thể sẽ mất nhiều thời gian ...
Egor Hans

1
Có khá nhiều JVM. Một cái thường thấy nhất trong thế giới doanh nghiệp nên là cái IBM, iirc, đi kèm với không gian web
Adrian Shum

0

Không có cách nào gần một lớp lót, nhưng tôi nghĩ đây là cách đơn giản nhất:

List<String> newList = new ArrayList<String>(l1);
newList.addAll(l2);

for(String w:newList)
        System.out.printf("%s ", w);

0

Đây là một cách tiếp cận sử dụng luồng và java 8 nếu danh sách của bạn có các loại khác nhau và bạn muốn kết hợp chúng với một danh sách loại khác.

public static void main(String[] args) {
    List<String> list2 = new ArrayList<>();
    List<Pair<Integer, String>> list1 = new ArrayList<>();

    list2.add("asd");
    list2.add("asdaf");
    list1.add(new Pair<>(1, "werwe"));
    list1.add(new Pair<>(2, "tyutyu"));

    Stream stream = Stream.concat(list1.stream(), list2.stream());

    List<Pair<Integer, String>> res = (List<Pair<Integer, String>>) stream
            .map(item -> {
                if (item instanceof String) {
                    return new Pair<>(0, item);
                }
                else {
                    return new Pair<>(((Pair<Integer, String>)item).getKey(), ((Pair<Integer, String>)item).getValue());
                }
            })
            .collect(Collectors.toList());
}

0

Nếu bạn muốn làm điều này một cách tĩnh, bạn có thể làm như sau.

Các ví dụ sử dụng 2 EnumSets theo thứ tự tự nhiên (== Enum-order) A, Bvà sau đó tham gia trong một ALLdanh sách.

public static final EnumSet<MyType> CATEGORY_A = EnumSet.of(A_1, A_2);
public static final EnumSet<MyType> CATEGORY_B = EnumSet.of(B_1, B_2, B_3);

public static final List<MyType> ALL = 
              Collections.unmodifiableList(
                  new ArrayList<MyType>(CATEGORY_A.size() + CATEGORY_B.size())
                  {{
                      addAll(CATEGORY_A);
                      addAll(CATEGORY_B);
                  }}
              );

Điều này sẽ tạo ra một lớp đồng nghĩa mới. Không nên tiếp cận!
kravemir

-3
import java.util.AbstractList;
import java.util.List;


/**
 * The {@code ConcatList} is a lightweight view of two {@code List}s.
 * <p>
 * This implementation is <em>not</em> thread-safe even though the underlying lists can be.
 * 
 * @param <E>
 *            the type of elements in this list
 */
public class ConcatList<E> extends AbstractList<E> {

    /** The first underlying list. */
    private final List<E> list1;
    /** The second underlying list. */
    private final List<E> list2;

    /**
     * Constructs a new {@code ConcatList} from the given two lists.
     * 
     * @param list1
     *            the first list
     * @param list2
     *            the second list
     */
    public ConcatList(final List<E> list1, final List<E> list2) {
        this.list1 = list1;
        this.list2 = list2;
    }

    @Override
    public E get(final int index) {
        return getList(index).get(getListIndex(index));
    }

    @Override
    public E set(final int index, final E element) {
        return getList(index).set(getListIndex(index), element);
    }

    @Override
    public void add(final int index, final E element) {
        getList(index).add(getListIndex(index), element);
    }

    @Override
    public E remove(final int index) {
        return getList(index).remove(getListIndex(index));
    }

    @Override
    public int size() {
        return list1.size() + list2.size();
    }

    @Override
    public boolean contains(final Object o) {
        return list1.contains(o) || list2.contains(o);
    }

    @Override
    public void clear() {
        list1.clear();
        list2.clear();
    }

    /**
     * Returns the index within the corresponding list related to the given index.
     * 
     * @param index
     *            the index in this list
     * 
     * @return the index of the underlying list
     */
    private int getListIndex(final int index) {
        final int size1 = list1.size();
        return index >= size1 ? index - size1 : index;
    }

    /**
     * Returns the list that corresponds to the given index.
     * 
     * @param index
     *            the index in this list
     * 
     * @return the underlying list that corresponds to that index
     */
    private List<E> getList(final int index) {
        return index >= list1.size() ? list2 : list1;
    }

}
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.