将列表分成n个列表的有效方法
我有一个数组,我想分成n个大小较小的数组,并执行每个操作。 我目前的做法是
用Java中的ArrayLists实现(任何伪代码都可以)
for (int i = 1; i <= Math.floor((A.size() / n)); i++) { ArrayList temp = subArray(A, ((i * n) - n), (i * n) - 1); // do stuff with temp } private ArrayList<Comparable> subArray(ArrayList A, int start, int end) { ArrayList toReturn = new ArrayList(); for (int i = start; i <= end; i++) { toReturn.add(A.get(i)); } return toReturn; }
其中A是列表,n是所需列表的大小
我相信在处理相当大的列表(大小高达一百万)时,这样做会花费太多时间,所以我试图找出更有效的方法。
你会想要做一些使用List.subList(int,int)视图而不是复制每个子列表。 要做到这一点很容易,使用Guava的Lists.partition(List,int)方法:
List<Foo> foos = ... for (List<Foo> partition : Lists.partition(foos, n)) { // do something with partition }
请注意,这与许多事情一样,对于不是RandomAccess
的List
(例如LinkedList
)来说效率不高。
如果您正在使用列表,我使用“ Apache Commons Collections 4 ”库。 它在ListUtils类中有一个分区方法:
... int targetSize = 100; List<Integer> largeList = ... List<List<Integer>> output = ListUtils.partition(largeList, targetSize);
例如:
int partitionSize = 10; List<List<String>> partitions = new ArrayList<>(); for (int i=0; i<yourlist.size(); i += partitionSize) { partitions.add(yourlist.subList(i, Math.min(i + partitionSize, yourlist.size()))); } for (List<String> list : partitions) { //Do your stuff on each sub list }
在我看到ColinD的回答(+1)之前,我自己写了一个,使用番石榴绝对是一种方法。 单独离开太有意思了,所以下面给你一份清单的副本,而不是意见,所以GUAVA肯定比这个更有效率。 我发布这个,因为写起来很有趣,而不是暗示它是有效的:
Hamcresttesting(无论如何):
assertThat(chunk(asList("a", "b", "c", "d", "e"), 2), equalTo(asList(asList("a", "b"), asList("c", "d"), asList("e"))));
代码:
public static <T> Iterable<Iterable<T>> chunk(Iterable<T> in, int size) { List<Iterable<T>> lists = newArrayList(); Iterator<T> i = in.iterator(); while (i.hasNext()) { List<T> list = newArrayList(); for (int j=0; i.hasNext() && j<size; j++) { list.add(i.next()); } lists.add(list); } return lists; }
public <E> Iterable<List<E>> partition(List<E> list, final int batchSize) { assert(batchSize > 0); assert(list != null); assert(list.size() + batchSize <= Integer.MAX_VALUE); //avoid overflow int idx = 0; List<List<E>> result = new ArrayList<List<E>>(); for (idx = 0; idx + batchSize <= list.size(); idx += batchSize) { result.add(list.subList(idx, idx + batchSize)); } if (idx < list.size()) { result.add(list.subList(idx, list.size())); } return result; }
如果你正在处理数组,你可以使用System.arraycopy() 。
int[] a = {1,2,3,4,5}; int[] b = new int[2]; int[] c = new int[3]; System.arraycopy(a, 0, b, 0, 2); // b will be {1,2} System.arraycopy(a, 2, c, 0, 3); // c will be {3,4,5}
关于什么
Arrays.copyOfRange( original, from, to )
?
我只是实现了一个列表分区,因为我不能使用一个库。
所以我想在这里分享我的代码:
import java.util.Iterator; import java.util.List; import java.util.NoSuchElementException; public class ListPartitioning<T> implements Iterable<List<T>> { private final List<T> list; private final int partitionSize; public ListPartitioning(List<T> list, int partitionSize) { if (list == null) { throw new IllegalArgumentException("list must not be null"); } if (partitionSize < 1) { throw new IllegalArgumentException("partitionSize must be 1 or greater"); } this.list = list; this.partitionSize = partitionSize; } @Override public Iterator<List<T>> iterator() { return new ListPartitionIterator<T>(list, partitionSize); } private static class ListPartitionIterator<T> implements Iterator<List<T>> { private int index = 0; private List<T> listToPartition; private int partitionSize; private List<T> nextPartition; public ListPartitionIterator(List<T> listToPartition, int partitionSize) { this.listToPartition = listToPartition; this.partitionSize = partitionSize; } @Override public boolean hasNext() { return index < listToPartition.size(); } @Override public List<T> next() { if (!hasNext()) { throw new NoSuchElementException(); } int partitionStart = index; int partitionEnd = Math.min(index + partitionSize, listToPartition.size()); nextPartition = listToPartition.subList(partitionStart, partitionEnd); index = partitionEnd; return nextPartition; } @Override public void remove() { if (nextPartition == null) { throw new IllegalStateException("next must be called first"); } nextPartition.clear(); index -= partitionSize; nextPartition = null; } } }
而且基于testng的unit testing。
import org.testng.Assert; import org.testng.annotations.Test; import java.util.*; public class ListPartitioningTest { @Test(expectedExceptions = IllegalArgumentException.class) public void nullList() { ListPartitioning<String> lists = new ListPartitioning<String>(null, 1); } @Test(groups = Group.UNIT_TEST, expectedExceptions = IllegalArgumentException.class) public void wrongPartitionSize() { ListPartitioning<String> lists = new ListPartitioning<String>(new ArrayList<String>(), 0); } @Test() public void iteratorTest() { List<Integer> integers = Arrays.asList(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); ListPartitioning<Integer> listPartitioning = new ListPartitioning<Integer>(integers, 7); Iterator<List<Integer>> partitionIterator = listPartitioning.iterator(); Assert.assertNotNull(partitionIterator); Assert.assertTrue(partitionIterator.hasNext(), "next partition (first)"); List<Integer> partition = partitionIterator.next(); Assert.assertEquals(partition, Arrays.asList(0, 1, 2, 3, 4, 5, 6)); Assert.assertTrue(partitionIterator.hasNext(), "next partition (second)"); partition = partitionIterator.next(); Assert.assertEquals(partition, Arrays.asList(7, 8, 9, 10, 11, 12, 13)); Assert.assertTrue(partitionIterator.hasNext(), "next partition (third)"); partition = partitionIterator.next(); Assert.assertEquals(partition, Arrays.asList(14, 15)); Assert.assertFalse(partitionIterator.hasNext()); } @Test(expectedExceptions = NoSuchElementException.class) public void noSuchElementException() { List<Integer> integers = Arrays.asList(1); ListPartitioning<Integer> listPartitioning = new ListPartitioning<Integer>(integers, 2); Iterator<List<Integer>> partitionIterator = listPartitioning.iterator(); List<Integer> partition = partitionIterator.next(); partition = partitionIterator.next(); } @Test(expectedExceptions = IllegalStateException.class) public void removeWithoutNext() { List<Integer> integers = new ArrayList<Integer>(Arrays.asList(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15)); ListPartitioning<Integer> listPartitioning = new ListPartitioning<Integer>(integers, 7); Iterator<List<Integer>> partitionIterator = listPartitioning.iterator(); partitionIterator.remove(); } @Test() public void remove() { List<Integer> integers = new ArrayList<Integer>(Arrays.asList(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15)); ListPartitioning<Integer> listPartitioning = new ListPartitioning<Integer>(integers, 7); Iterator<List<Integer>> partitionIterator = listPartitioning.iterator(); partitionIterator.next(); partitionIterator.next(); partitionIterator.remove(); Assert.assertTrue(partitionIterator.hasNext(), "next partition "); List<Integer> partition = partitionIterator.next(); Assert.assertEquals(partition, Arrays.asList(14, 15)); Assert.assertFalse(partitionIterator.hasNext()); Assert.assertEquals(integers, Arrays.asList(0, 1, 2, 3, 4, 5, 6, 14, 15)); } }