Skip to content

Instantly share code, notes, and snippets.

@revers-back
Created October 11, 2017 11:12
Show Gist options
  • Save revers-back/2abae413b055a56de0e19dfdd896c3de to your computer and use it in GitHub Desktop.
Save revers-back/2abae413b055a56de0e19dfdd896c3de to your computer and use it in GitHub Desktop.
DataList with pagination
/**
* List для работы с пагинацией
* Имеет лимит и смещение
* Можно сливать с другим DataList
*
* @param <T> Item
*/
public class DataList<T> implements List<T>, Serializable {
public static final int UNSPECIFIED_PAGE = -1;
public static final int UNSPECIFIED_PAGE_SIZE = -1;
public static final int UNSPECIFIED_TOTAL_ITEMS_COUNT = -1;
public static final int UNSPECIFIED_TOTAL_PAGES_COUNT = -1;
private int pageSize;
private int startPage;
private int numPages;
private int totalItemsCount;
private int totalPagesCount;
private ArrayList<T> data;
@FunctionalInterface
public interface MapFunc<R, T> {
R call(T item);
}
public DataList(Collection<T> data, int page, int pageSize) {
this(data, page, 1, pageSize);
}
public DataList(Collection<T> data, int page, int pageSize, int totalItemsCount, int totalPagesCount) {
this(data, page, 1, pageSize, totalItemsCount, totalPagesCount);
}
private DataList(Collection<T> data, int page, int numPages, int pageSize) {
this(data, page, numPages, pageSize, UNSPECIFIED_TOTAL_ITEMS_COUNT, UNSPECIFIED_TOTAL_PAGES_COUNT);
}
private DataList(Collection<T> data, int page, int numPages, int pageSize, int totalItemsCount, int totalPagesCount) {
this.data = new ArrayList<>();
this.data.addAll(data);
this.startPage = page;
this.pageSize = pageSize;
this.numPages = numPages;
this.totalItemsCount = totalItemsCount;
this.totalPagesCount = totalPagesCount;
}
public static <T> DataList<T> empty() {
return new DataList<>(new ArrayList<>(), UNSPECIFIED_PAGE, 0, UNSPECIFIED_PAGE_SIZE, 0, 0);
}
/**
* Слияние двух DataList
*
* @param inputDataList DataList для слияния с текущим
* @return текущий экземпляр
*/
public DataListMergeChanges merge(DataList<T> inputDataList) {
if (this.startPage != UNSPECIFIED_PAGE
&& inputDataList.startPage != UNSPECIFIED_PAGE
&& this.pageSize != inputDataList.pageSize) {
throw new IllegalArgumentException("pageSize for merging DataList must be same");
}
int lastSize = this.data.size();
Map<Integer, List<T>> originalPagesData = split();
Map<Integer, List<T>> inputPagesData = inputDataList.split();
SortedMap<Integer, List<T>> resultPagesData = new TreeMap<>();
resultPagesData.putAll(originalPagesData);
resultPagesData.putAll(inputPagesData);
ArrayList<T> newData = new ArrayList<>();
int lastPage = UNSPECIFIED_PAGE;
int lastPageItemsSize = -1;
for (Map.Entry<Integer, List<T>> pageData : resultPagesData.entrySet()) {
Integer pageNumber = pageData.getKey();
List<T> pageItems = pageData.getValue();
if (lastPage != UNSPECIFIED_PAGE &&
(pageNumber - lastPage > 1 || lastPageItemsSize < pageSize)) {
Logger.e(new IncompatibleRangesException("Merging DataLists has empty space " +
"between its ranges, original list: " + this + ", inputList: " + inputDataList));
break;
}
lastPage = pageNumber;
lastPageItemsSize = pageItems.size();
newData.addAll(pageItems);
}
this.data = newData;
this.startPage = resultPagesData.firstKey();
this.numPages = lastPage - startPage + 1;
this.totalItemsCount = inputDataList.totalItemsCount == UNSPECIFIED_TOTAL_ITEMS_COUNT
? this.totalItemsCount
: inputDataList.totalItemsCount;
this.totalPagesCount = inputDataList.totalPagesCount == UNSPECIFIED_TOTAL_PAGES_COUNT
? this.totalPagesCount
: inputDataList.totalPagesCount;
if (inputDataList.pageSize != UNSPECIFIED_PAGE_SIZE) {
this.pageSize = inputDataList.pageSize;
}
return new DataListMergeChanges(lastSize, inputDataList.size(), inputDataList.getStartPage(), pageSize);
}
/**
* разделяет данные на блоки по страницам
*
* @return
*/
private Map<Integer, List<T>> split() {
Map<Integer, List<T>> result = new HashMap<>();
for (int i = startPage; i < startPage + numPages; i++) {
int startItemIndex = (i - startPage) * pageSize;
int itemsRemained = data.size() - startItemIndex;
int endItemIndex = startItemIndex +
(itemsRemained < pageSize ? itemsRemained : pageSize);
result.put(i, data.subList(startItemIndex, endItemIndex));
}
return result;
}
public <R> DataList<R> transform(MapFunc<R, T> mapFunc) {
List<R> resultData = new ArrayList<R>();
for (T item : this) {
resultData.add(mapFunc.call(item));
}
return new DataList<>(resultData, startPage, numPages, pageSize, this.totalItemsCount, this.totalPagesCount);
}
/**
* @return размер одной страницы
*/
public int getPageSize() {
return pageSize;
}
/**
* @return первая страница
*/
public int getStartPage() {
return startPage;
}
/**
* @return количество страниц
*/
public int getNumPages() {
return numPages;
}
/**
* возвращает значение offset c которого нужно начать чтобы подгрузить слкдующий блок данных
*/
public int getNextPage() {
return startPage == UNSPECIFIED_PAGE ? 1 : startPage + numPages;
}
/**
* @return возможное количество элементов для загружки
*/
public int getTotalItemsCount() {
return totalItemsCount;
}
/**
* @return возможное количество страниц для загрузки
*/
public int getTotalPagesCount() {
return totalPagesCount;
}
/**
* Проверка возможности дозагрузки данных
*
* @return
*/
public boolean canGetMore() {
return startPage == UNSPECIFIED_PAGE
|| (data.size() == (numPages - startPage + 1) * pageSize
&& totalPagesCount != numPages);
}
@Override
public int size() {
return data.size();
}
@Override
public boolean isEmpty() {
return data.isEmpty();
}
@Override
public boolean contains(Object o) {
return data.contains(o);
}
@NonNull
@Override
public Iterator<T> iterator() {
return data.iterator();
}
@NonNull
@Override
public Object[] toArray() {
return data.toArray();
}
@NonNull
@Override
public <T1> T1[] toArray(T1[] a) {
return data.toArray(a);
}
@Override
public boolean add(T t) {
throw new UnsupportedOperationException();
}
@Override
public boolean remove(Object o) {
throw new UnsupportedOperationException();
}
@Override
public boolean containsAll(Collection<?> c) {
return data.containsAll(c);
}
@Override
public boolean addAll(Collection<? extends T> c) {
throw new UnsupportedOperationException();
}
@Override
public boolean addAll(int index, Collection<? extends T> c) {
throw new UnsupportedOperationException();
}
@Override
public boolean removeAll(Collection<?> c) {
throw new UnsupportedOperationException();
}
@Override
public boolean retainAll(Collection<?> c) {
throw new UnsupportedOperationException();
}
@Override
public void clear() {
this.data.clear();
startPage = UNSPECIFIED_PAGE;
pageSize = UNSPECIFIED_PAGE_SIZE;
numPages = 0;
totalItemsCount = UNSPECIFIED_TOTAL_ITEMS_COUNT;
totalPagesCount = UNSPECIFIED_TOTAL_PAGES_COUNT;
}
@Override
public T get(int index) {
return data.get(index);
}
@Override
public T set(int index, T element) {
return data.set(index, element);
}
@Override
public void add(int index, T element) {
throw new UnsupportedOperationException();
}
@Override
public T remove(int index) {
return data.remove(index);
}
@Override
public int indexOf(Object o) {
return data.indexOf(o);
}
@Override
public int lastIndexOf(Object o) {
return data.lastIndexOf(o);
}
@Override
public ListIterator<T> listIterator() {
return data.listIterator();
}
@NonNull
@Override
public ListIterator<T> listIterator(int index) {
return data.listIterator(index);
}
@NonNull
@Override
public List<T> subList(int fromIndex, int toIndex) {
return data.subList(fromIndex, toIndex);
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof DataList)) return false;
DataList<?> dataList = (DataList<?>) o;
if (pageSize != dataList.pageSize) return false;
if (startPage != dataList.startPage) return false;
if (numPages != dataList.numPages) return false;
return data != null ? data.equals(dataList.data) : dataList.data == null;
}
@Override
public int hashCode() {
int result = pageSize;
result = 31 * result + startPage;
result = 31 * result + numPages;
result = 31 * result + (data != null ? data.hashCode() : 0);
return result;
}
@Override
public String toString() {
return "DataList{" +
"pageSize=" + pageSize +
", startPage=" + startPage +
", numPages=" + numPages +
", totalItemsCount=" + totalItemsCount +
", totalPagesCount=" + totalPagesCount +
", data=" + data +
'}';
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment