1 /*
2 * Copyright (C) 2013 Martin Cerny
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18 package cz.cuni.amis.utils.collections;
19
20 import java.util.*;
21
22 /**
23 * An unmodifiable list that combines several child lists.
24 * The list represent view on the underlying lists, so if they are modified,
25 * so is this list. This class is not thread-safe (i.e. parallel modification to
26 * underlying lists may cause unexpected behaviour)
27 * @author Martin Cerny
28 */
29 public class ListConcatenation<T> extends AbstractList<T> {
30
31 private List<List<T>> lists;
32
33 public static <T> List<T> concatenate(List<T> ... lists){
34 return concatenate(Arrays.asList(lists));
35 }
36
37 /**
38 * Concatenates lists into the most simple form.
39 * <ul>
40 * <li>Empty lists are ommitted</li>
41 * <li>If there is only one non-empty list, the list is returned, instead of concatenation</li>
42 * <li>If there is another ListConcatenation among parameters, it is expanded and its components are taken directly </li>
43 * </ul>
44 * @param <T>
45 * @param lists
46 * @return
47 */
48 public static <T> List<T> concatenate(List<List<T>> lists){
49 if(lists.isEmpty()){
50 return Collections.EMPTY_LIST;
51 } else {
52 List<List<T>> nonEmptyBasicLists = new ArrayList<List<T>>(lists.size());
53 for (List<T> list : lists) {
54 if (list instanceof ListConcatenation) {
55 nonEmptyBasicLists.addAll(((ListConcatenation<T>) list).lists);
56 } else {
57 if (!list.isEmpty()) {
58 nonEmptyBasicLists.add(list);
59 }
60 }
61 }
62 if (lists.size() == 1) {
63 return lists.get(0);
64 } else {
65 return new ListConcatenation<T>(lists);
66 }
67 }
68 }
69
70 public ListConcatenation(List<List<T>> lists) {
71 this.lists = new ArrayList<List<T>>(lists);
72 }
73
74 public ListConcatenation(List<T> ... lists){
75 this.lists = Arrays.asList(lists);
76 }
77
78 @Override
79 public T get(int index) {
80 int listId = 0;
81 while(listId < lists.size() && index >= lists.get(listId).size()){
82 index -= lists.get(listId).size();
83 listId++;
84 }
85 if(listId > lists.size()){
86 throw new IndexOutOfBoundsException("Index: " + index);
87 }
88
89 return lists.get(listId).get(index);
90 }
91
92 @Override
93 public int size() {
94 int totalSize = 0;
95 for(List<T> list : lists){
96 totalSize += list.size();
97 }
98 return totalSize;
99 }
100
101
102
103 }