2011-04-28 65 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

相關問題