2011-04-28 67 views
34

我有一个数组,我想将它分成n个较小的数组,并对每个数组执行操作。 我现在这样做的方法是在Java中的ArrayList实现将列表划分为n个列表的有效方法

(任何伪代码会做)

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是所需的列表的大小

我相信这种方式在处理相当大的列表(大小高达100万)时需要花费太多时间,所以我试图找出更有效的方法。

回答

76

你会想要做一些使用List.subList(int, int)的意见,而不是复制每个子列表。要做到这一点真的很容易,使用GuavaLists.partition(List, int)方法:

List<Foo> foos = ... 
for (List<Foo> partition : Lists.partition(foos, n)) { 
    // do something with partition 
} 

注意这一点,像许多事情,是不是很有效,用List不是RandomAccess(如LinkedList)。

+3

+1不错!我需要更好地学习番石榴API ... – alpian 2011-04-28 21:10:23

+1

如果你有一个'Iterable'而不是'List',还有'Iterables.partition(Iterable,int)' – Krease 2015-12-16 00:16:51

+0

最后一个链接已经改变了,我想这是一个https://google.github.io/guava/releases/19.0/api/docs/com/google/common/collect/Lists.html#partition(java.util.List,int) – 2016-12-20 09:44:52

0

如果您正在处理阵列,那么您可以使用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} 
0

什么

Arrays.copyOfRange(original, from, to) 

3

嗯,在我看到ColinD的回答(+1)之前,我写了一篇自己的文章,并且使用番石榴绝对是最佳选择。单独离开太有意思了,所以下面给你一份清单的副本,而不是视图,所以GUAVA的确比这个更有效率。我张贴这一点,因为这很有趣写,而不是暗示它是有效的:

的Hamcrest测试(反正一个):

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; 
} 
2
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; 
} 
0

我只是实现了一个列表分区适应,因为我无法使用库。

所以我想在这里分享我的代码:

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的单元测试。

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)); 
    } 
} 
4

例如:

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 
    } 
+0

绝对是最好的答案 – 2017-10-05 23:22:19

相关问题