问题
I have 3 List
of different kind of Objects
.
For example:
List
A
contains 64
elements.
List
B
contains 33
elements.
List
C
contains 515
elements.
So in total, I have 612
elements.
I want to make groups (Pagination
) of 100
elements, for example, it would look like this:
Page 1
: List
A
: 64
elements / List
B
: 33
elements / List
C
: 3
elements
Page 2
: List
A
: 0
elements / List
B
: 0
elements / List
C
: 100
elements
Page 3
: List
A
: 0
elements / List
B
: 0
elements / List
C
: 100
elements
Page 4
: List
A
: 0
elements / List
B
: 0
elements / List
C
: 100
elements
Page 5
: List
A
: 0
elements / List
B
: 0
elements / List
C
: 100
elements
Page 6
: List
A
: 0
elements / List
B
: 0
elements / List
C
: 100
elements
Page 7
: List
A
: 0
elements / List
B
: 0
elements / List
C
: 12
elements
My idea is creating a Map<Integer, List<List>
where the key
would be the Page
and the value
a List
which contains 3 Lists
(one for each List
A
, B
or C
).
Here is my code:
int totalPages = 0;
int totalElements = listA.size() + listB.size() + listC.size();
if(totalElements % PAGE_SIZE == 0) {
totalPages = totalElements / PAGE_SIZE;
}else {
totalPages = (totalElements / PAGE_SIZE) + 1;
}
Map<Integer, List<List<ParentObject>>> paginatedMap = new HashMap<Integer, List<List<ParentObject>>>();
for(int i=0; i<totalPages; i++) {
List<List<ParentObject>> list = new LinkedList<List<ParentObject>>();
List<ObjectA> subListA = new LinkedList<ObjectA>();
List<ObjectB> subListB = new LinkedList<ObjectB>();
List<ObjectC> subListC = new LinkedList<ObjectC>();
int total = 0;
if(total <= PAGE_SIZE) {
subListA.addAll(listA.subList(0, (PAGE_SIZE-total)-1));
listA.removeAll(listA.subList(0, (PAGE_SIZE-total)-1));
total = total + subListA.size();
}
if(total <= PAGE_SIZE) {
subListB.addAll(listB.subList(0, (PAGE_SIZE-total)-1));
listB.removeAll(listB.subList(0, (PAGE_SIZE-total)-1));
total = total + subListB.size();
}
if(total <= PAGE_SIZE) {
subListC.addAll(listC.subList(0, (PAGE_SIZE-total)-1));
listC.removeAll(listC.subList(0, (PAGE_SIZE-total)-1));
total = total + subListC.size();
}
list.add(subListA);
list.add(subListB);
list.add(subListC);
paginatedMap.put(i, list);
}
where PAGE_SIZE
is 100
That's not working because of course I need to check how many elements each list
contains before calling the subList
method
.
I think I'm taking the wrong way, but I don't see another way to do it.
Any ideas?
Thanks!
Finally I got it to work. Here is the code:
private Map<Integer, List<List<MyObject>>> paginateDataRequest(List<List<MyObject>> requestLists, double pageSize) {
Map<Integer, List<List<MyObject>>> result = new LinkedHashMap<Integer, List<List<MyObject>>>();
int totalElements = 0;
//We calculate the total of the elements contained in the requestLists.
for(List<MyObject> subList : requestLists) {
if(subList != null) {
totalElements += subList.size();
}
}
//We round it up. The result Map will contain x pages with {pageSize} elements each one. For example, if the total amount of request is 101,
//our Map will have 2 pages (100 elements + 1 element)
int totalRequests = (int)Math.ceil(totalElements / pageSize);
//We iterate over each page
for(int i=0; i<totalRequests; i++) {
List<List<MyObject>> entry = new LinkedList<List<MyObject>>();
int freeElements = (int)pageSize;
for(List<MyObject> list : requestLists) {
List<MyObject> subList = new LinkedList<MyObject>();
if(freeElements > 0) {
if(list.size() > freeElements) {
subList.addAll(list.subList(0, freeElements));
}else {
subList.addAll(list);
}
//We update the left free elements
freeElements -= subList.size();
}
entry.add(subList);
list.removeAll(subList);
}
//We add a new page to the result Map
result.put(i, entry);
}
return result;
}
Thanks everyone for helping!
回答1:
That's not working because of course I need to check how many elements each
list
contains before calling thesubList
method.
This only seems to be the problem, if you are not willing to check the size of the list. Make the subList at most as large as the whole list by checking the size first...
Also instead of
listB.removeAll(listB.subList(0, (PAGE_SIZE-total)-1));
you should use
listB.subList(0, (PAGE_SIZE-total)-1).clear();
to prevent equal elements from being removed accidentally.
The below approach presents a more reusable way to do the task, since it does not rely on a specific number of lists and also does not modify the source lists:
Convert the input data structure from 3 seperate List
s to a list containing those lists. This allows you to keep track of the index of the list to get the elements from as well as the first index of a element in this list not used yet. This way you can simply go through the lists and add items, until the page is full.
The following code returns a List
instead of a Map
, since the keys are the numbers 0, ..., n, but it could easily be modified to return a map:
public static <T> List<List<List<T>>> paginate(List<? extends List<? extends T>> objects, final int pageSize) {
List<List<List<T>>> result = new ArrayList<>();
int index = 0;
int size = objects.size();
// skip empty lists
while (index < size && objects.get(index).isEmpty()) {
index++;
}
for (int pageIndex = 0; index < size;) {
int remaining = pageSize;
List<List<T>> page = new ArrayList<>(size);
result.add(page);
for (int i = 0; i < index; i++) {
page.add(Collections.emptyList());
}
while (remaining > 0 && index < size) {
List<? extends T> source = objects.get(index);
int lastIndex = Math.min(source.size(), pageIndex + remaining);
List<T> list = new ArrayList<>(source.subList(pageIndex, lastIndex));
page.add(list);
remaining -= lastIndex - pageIndex;
if (lastIndex == source.size()) {
index++;
pageIndex = 0;
// skip empty lists
while (index < size && objects.get(index).isEmpty()) {
page.add(Collections.emptyList());
index++;
}
} else {
pageIndex = lastIndex;
}
}
for (int i = page.size(); i < size; i++) {
page.add(Collections.emptyList());
}
}
return result;
}
回答2:
Naive solution building a global list each time (the advantege beeing that it always takes the last version of underlying lists).
public class ListPager {
public List<List<Object>> lists = new ArrayList<List<Object>>();
public int _pageSize = 100;
public void addList(List<Object> list) {
lists.add(list);
}
public List<Object> getPage(int p) {
List<Object> global = new ArrayList<Object>();
for (List<Object> l : lists) {
global.addAll(l);
}
if (p*_pageSize > global.size()) return global;
int maxBound = (p + 1)*_pageSize;
if (maxBound > global.size()) {
maxBound = p*_pageSize + (global.size()%(p*_pageSize));
}
return global.subList(p*_pageSize, maxBound);
}
}
associated test class:
public class ListPagerTest {
public static class ObjectA {
public String toString() { return "A"; }
}
public static class ObjectB {
public String toString() { return "B"; }
}
public static class ObjectC {
public String toString() { return "C"; }
}
@Test
public void test() {
List<Object> listA = new ArrayList<Object>();
for (int i = 0 ; i < 64 ; i++) { listA.add(new ObjectA()); }
List<Object> listB = new ArrayList<Object>();
for (int i = 0 ; i < 33 ; i++) { listB.add(new ObjectB()); }
List<Object> listC = new ArrayList<Object>();
for (int i = 0 ; i < 515 ; i++) { listC.add(new ObjectC()); }
ListPager lp = new ListPager();
lp.addList(listA);
lp.addList(listB);
lp.addList(listC);
for (int i = 0 ; i < 7 ; i++) {
System.out.println("Page " + i);
print(lp.getPage(i));
}
}
public static void print(List<Object> l) {
StringBuffer out = new StringBuffer();
for (Object o : l) out.append(o + ",");
System.out.println(out.toString());
}
}
回答3:
You can put all the different objects in one List,and then use instanceof
to detect class type.
来源:https://stackoverflow.com/questions/36424856/java-paginated-list