Java Paginated List

馋奶兔 提交于 2019-12-12 02:49:29

问题


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 the subList 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 Lists 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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!