List 等分实现方式
2019-02-22 本文已影响0人
阿福德
背景:
今天要做批量插入,得到一个List,为了防止一次插入的数据量太多,于是考虑分批次,这就需要将list进行等分。
于是决定原有的代码中应该有这种工具类,找了一下,真找到了ListTools.java, 不过看了一下,这个实现方式效率较低
其中的实现如下:
public static <T> List<List<T>> partition1(List<T> list, int pageSize) {
int listSize = list.size();
int page = (listSize + (pageSize - 1)) / pageSize;
List<List<T>> listArray = new ArrayList<List<T>>();
for (int i = 0; i < page; i++) {
List<T> subList = new ArrayList<T>();
for (int j = 0; j < listSize; j++) {
int pageIndex = ((j + 1) + (pageSize - 1)) / pageSize;
if (pageIndex == (i + 1)) {
subList.add(list.get(j));
}
if ((j + 1) == ((j + 1) * pageSize)) {
break;
}
}
listArray.add(subList);
}
return listArray;
}
较好的List等分实现方式
public static <T> List<List<T>> partition2(List<T> list, int batchSize) {
int totalSize = list.size();
List<List<T>> retList = new ArrayList<>();
if(totalSize < batchSize) {
retList.add(list);
return retList;
}
int batchNum = totalSize % batchSize ==0 ? totalSize / batchSize : totalSize / batchSize + 1;
for(int i=0;i < batchNum; i++ ) {
int start = i * batchSize;
int end = (i+1) * batchSize;
if(end > totalSize) {
end = totalSize;
}
retList.add(list.subList(start, end));
}
return retList;
}
更好的实现方式
public static <T> List<List<T>> partition3(List<T> list, int size) {
return (list instanceof RandomAccess)
? new RandomAccessPartition<T>(list, size)
: new Partition<T>(list, size);
}
private static class Partition<T> extends AbstractList<List<T>> {
final List<T> list;
final int size;
Partition(List<T> list, int size) {
this.list = list;
this.size = size;
}
@Override
public List<T> get(int index) {
int start = index * size;
int end = Math.min(start + size, list.size());
return list.subList(start, end);
}
@Override
public int size() {
return divide(list.size(), size);
}
@Override
public boolean isEmpty() {
return list.isEmpty();
}
}
public static int divide(int p, int q) {
int div = p / q;
// equal to p % q
int rem = p - q * div;
if (rem == 0) {
return div;
}
int signum = 1 | ((p ^ q) >> (Integer.SIZE - 1));
boolean increment = signum > 0;
return increment ? div + signum : div;
}
private static class RandomAccessPartition<T> extends Partition<T> implements RandomAccess {
RandomAccessPartition(List<T> list, int size) {
super(list, size);
}
}
性能
编写一个测试main程序
public static void main(String[] args) {
List<String> list = new ArrayList<>();
for(int i=0;i<1000000;i++) {
list.add("A"+i);
}
long start = System.currentTimeMillis();
List<List<String>> ret = partition1(list, 100);
System.out.println("partition1:"+ (System.currentTimeMillis() - start));
start = System.currentTimeMillis();
List<List<String>> ret2 = partition2(list, 100);
System.out.println("partition2:"+ (System.currentTimeMillis() - start));
start = System.currentTimeMillis();
List<List<String>> ret3 = partition3(list, 100);
System.out.println("partition3:"+(System.currentTimeMillis() - start));
System.out.println(ret.size() +" " + ret2.size());
}
结果:
image.png