Java:如何将 ArrayList 拆分为多个小的 ArrayList?

Posted

技术标签:

【中文标题】Java:如何将 ArrayList 拆分为多个小的 ArrayList?【英文标题】:Java: how can I split an ArrayList in multiple small ArrayLists? 【发布时间】:2011-02-23 03:10:52 【问题描述】:

如何将一个 ArrayList (size=1000) 拆分为多个相同大小 (=10) 的 ArrayList?

ArrayList<Integer> results;

【问题讨论】:

您需要视图或新集合吗? Java 8 : ***.com/a/51837311/1216775 【参考方案1】:

您可以使用subList(int fromIndex, int toIndex) 来查看原始列表的一部分。

来自 API:

返回此列表在指定的fromIndex(包括)和toIndex(不包括)之间的视图。 (如果fromIndextoIndex 相等,则返回列表为空。)返回列表由此列表支持,因此返回列表中的非结构性更改会反映在此列表中,反之亦然。返回的列表支持此列表支持的所有可选列表操作。

例子:

List<Integer> numbers = new ArrayList<Integer>(
    Arrays.asList(5,3,1,2,9,5,0,7)
);

List<Integer> head = numbers.subList(0, 4);
List<Integer> tail = numbers.subList(4, 8);
System.out.println(head); // prints "[5, 3, 1, 2]"
System.out.println(tail); // prints "[9, 5, 0, 7]"

Collections.sort(head);
System.out.println(numbers); // prints "[1, 2, 3, 5, 9, 5, 0, 7]"

tail.add(-1);
System.out.println(numbers); // prints "[1, 2, 3, 5, 9, 5, 0, 7, -1]"

如果您需要这些截断的列表不是视图,那么只需从subList 创建一个新的List。下面是一个将这些东西放在一起的例子:

// chops a list into non-view sublists of length L
static <T> List<List<T>> chopped(List<T> list, final int L) 
    List<List<T>> parts = new ArrayList<List<T>>();
    final int N = list.size();
    for (int i = 0; i < N; i += L) 
        parts.add(new ArrayList<T>(
            list.subList(i, Math.min(N, i + L)))
        );
    
    return parts;



List<Integer> numbers = Collections.unmodifiableList(
    Arrays.asList(5,3,1,2,9,5,0,7)
);
List<List<Integer>> parts = chopped(numbers, 3);
System.out.println(parts); // prints "[[5, 3, 1], [2, 9, 5], [0, 7]]"
parts.get(0).add(-1);
System.out.println(parts); // prints "[[5, 3, 1, -1], [2, 9, 5], [0, 7]]"
System.out.println(numbers); // prints "[5, 3, 1, 2, 9, 5, 0, 7]" (unmodified!)

【讨论】:

【参考方案2】:

您可以将Guava 库添加到您的项目中并使用Lists.partition 方法,例如

List<Integer> bigList = ...
List<List<Integer>> smallerLists = Lists.partition(bigList, 10);

【讨论】:

修改源列表,while循环遍历子列表,会得到并发异常,因为java doc stats : 外层列表不可修改,但反映源列表的最新状态。内部列表是原始列表的子列表视图。这是【参考方案3】:

Apache Commons Collections 4 在ListUtils 类中有一个partition 方法。它是这样工作的:

import org.apache.commons.collections4.ListUtils;
...

int targetSize = 100;
List<Integer> largeList = ...
List<List<Integer>> output = ListUtils.partition(largeList, targetSize);

【讨论】:

【参考方案4】:

polygenelubricants 提供的答案根据给定大小拆分数组。我正在寻找将数组拆分为给定数量的部分的代码。这是我对代码所做的修改:

public static <T>List<List<T>> chopIntoParts( final List<T> ls, final int iParts )

    final List<List<T>> lsParts = new ArrayList<List<T>>();
    final int iChunkSize = ls.size() / iParts;
    int iLeftOver = ls.size() % iParts;
    int iTake = iChunkSize;

    for( int i = 0, iT = ls.size(); i < iT; i += iTake )
    
        if( iLeftOver > 0 )
        
            iLeftOver--;

            iTake = iChunkSize + 1;
        
        else
        
            iTake = iChunkSize;
        

        lsParts.add( new ArrayList<T>( ls.subList( i, Math.min( iT, i + iTake ) ) ) );
    

    return lsParts;

希望它对某人有所帮助。

【讨论】:

【参考方案5】:

Java 8

我们可以根据某些大小或条件拆分列表。

static Collection<List<Integer>> partitionIntegerListBasedOnSize(List<Integer> inputList, int size) 
        return inputList.stream()
                .collect(Collectors.groupingBy(s -> (s-1)/size))
                .values();

static <T> Collection<List<T>> partitionBasedOnSize(List<T> inputList, int size) 
        final AtomicInteger counter = new AtomicInteger(0);
        return inputList.stream()
                    .collect(Collectors.groupingBy(s -> counter.getAndIncrement()/size))
                    .values();

static <T> Collection<List<T>> partitionBasedOnCondition(List<T> inputList, Predicate<T> condition) 
        return inputList.stream().collect(Collectors.partitioningBy(s-> (condition.test(s)))).values();

那么我们可以将它们用作:

final List<Integer> list = Arrays.asList(1,2,3,4,5,6,7,8,9,10);
System.out.println(partitionIntegerListBasedOnSize(list, 4));  // [[1, 2, 3, 4], [5, 6, 7, 8], [9, 10]]
System.out.println(partitionBasedOnSize(list, 4));  // [[1, 2, 3, 4], [5, 6, 7, 8], [9, 10]]
System.out.println(partitionBasedOnSize(list, 3));  // [[1, 2, 3], [4, 5, 6], [7, 8, 9], [10]]
System.out.println(partitionBasedOnCondition(list, i -> i<6));  // [[6, 7, 8, 9, 10], [1, 2, 3, 4, 5]]

【讨论】:

@i_am_zero 是否可以应用多个条件(第三种静态方法),以便您可以创建多个列表,例如[[1,2,3,4], [5,6,7,8,9], [10,11,12,13,14]] 条件:i=10 @gooornik07 一个流只能使用一次。【参考方案6】:

这对我有用

/**
* Returns List of the List argument passed to this function with size = chunkSize
* 
* @param largeList input list to be portioned
* @param chunkSize maximum size of each partition
* @param <T> Generic type of the List
* @return A list of Lists which is portioned from the original list 
*/
public static  <T> List<List<T>> chunkList(List<T> list, int chunkSize) 
    if (chunkSize <= 0) 
        throw new IllegalArgumentException("Invalid chunk size: " + chunkSize);
    
    List<List<T>> chunkList = new ArrayList<>(list.size() / chunkSize);
    for (int i = 0; i < list.size(); i += chunkSize) 
        chunkList.add(list.subList(i, i + chunkSize >= list.size() ? list.size()-1 : i + chunkSize));
    
    return chunkList;

例如:

List<Integer> stringList = new ArrayList<>();
stringList.add(0);
stringList.add(1);
stringList.add(2);
stringList.add(3);
stringList.add(4);
stringList.add(5);
stringList.add(6);
stringList.add(7);
stringList.add(8);
stringList.add(9);

List<List<Integer>> chunkList = getChunkList1(stringList, 2);

【讨论】:

请注意这有一个错误,它忽略了最后一组数据。 ex 201 分成 100 个块将返回 100,100,0 而不是 100,100,1【参考方案7】:

Java8 流,一个表达式,没有其他库:

List<String> input = ...
int partitionSize = ...

 Collection<List<String>> partitionedList = IntStream.range(0, input.size())
    .boxed()
        .collect(Collectors.groupingBy(partition -> (partition / partitionSize), Collectors.mapping(elementIndex -> input.get(elementIndex), Collectors.toList())))
            .values();

测试

List<String> input = Arrays.asList("a", "b", "c", "d", "e", "f", "g", "h" ,"i");

partitionSize = 1 -> [[a], [b], [c], [d], [e], [f], [g], [h], [I]]

partitionSize = 2 -> [[a, b], [c, d], [e, f], [g, h], [I]]

partitionSize = 3 -> [[a, b, c], [d, e, f], [g, h, I]]

partitionSize = 7 -> [[a, b, c, d, e, f, g], [h, I]]

partitionSize = 100 -> [[a, b, c, d, e, f, g, h, i]]

【讨论】:

这个答案被低估了。 2021 年底最干净的方法【参考方案8】:
private ArrayList<List<String>> chunkArrayList(ArrayList<String> arrayToChunk, int chunkSize) 
    ArrayList<List<String>> chunkList = new ArrayList<>();
    int guide = arrayToChunk.size();
    int index = 0;
    int tale = chunkSize;
    while (tale < arrayToChunk.size())
            chunkList.add(arrayToChunk.subList(index, tale));
            guide = guide - chunkSize;
            index = index + chunkSize;
            tale = tale + chunkSize;
    
    if (guide >0) 
       chunkList.add(arrayToChunk.subList(index, index + guide));
    
    Log.i("Chunked Array: " , chunkList.toString());
    return chunkList;

示例

    ArrayList<String> test = new ArrayList<>();
    for (int i=1; i<=1000; i++)
        test.add(String.valueOf(i));
    

    chunkArrayList(test,10);

输出

分块:: [[1, 2, 3, 4, 5, 6, 7, 8, 9, 10], [11, 12, 13, 14, 15, 16, 17, 18, 19, 20] , [21, 22, 23, 24, 25, 26, 27, 28, 29, 30], [31, 32, 33, 34, 35, 36, 37, 38, 39, 40], [41, 42, 43, 44, 45, 46, 47, 48, 49, 50], [51, 52, 53, 54, 55, 56, 57, 58, 59, 60], [61, 62, 63, 64, 65, 66, 67, 68, 69, 70], [71, 72, 73, 74, 75, 76, 77, 78, 79, 80], [81, 82, 83, 84, 85, 86, 87, 88, 89, 90], [91, 92, 93, 94, 95, 96, 97, 98, 99, 100],......

你会在你的日志中看到

【讨论】:

【参考方案9】:

我猜您遇到的问题是命名 100 个 ArrayList 并填充它们。您可以创建一个 ArrayList 数组并使用循环填充每个数组。

最简单(读起来最愚蠢)的方法是这样的:

ArrayList results = new ArrayList(1000);
    // populate results here
    for (int i = 0; i < 1000; i++) 
        results.add(i);
    
    ArrayList[] resultGroups = new ArrayList[100];
    // initialize all your small ArrayList groups
    for (int i = 0; i < 100; i++) 
            resultGroups[i] = new ArrayList();
    
    // put your results into those arrays
    for (int i = 0; i < 1000; i++) 
       resultGroups[i/10].add(results.get(i));
     

【讨论】:

【参考方案10】:

这里讨论了一个类似的问题,Java: split a List into two sub-Lists?

主要可以使用子列表。更多细节在这里:subList

返回此列表在 fromIndex(包括)和 toIndex(不包括)之间部分的视图。 (如果 fromIndex 和 toIndex 相等,则返回列表为空。)返回列表由此列表支持,因此返回列表中的更改会反映在此列表中,反之亦然。返回的列表支持此列表支持的所有可选列表操作...

【讨论】:

【参考方案11】:

你可以使用Eclipse Collections中的chunk方法:

ArrayList<Integer> list = new ArrayList<>(Interval.oneTo(1000));
RichIterable<RichIterable<Integer>> chunks = Iterate.chunk(list, 10);
Verify.assertSize(100, chunks);

chunk 方法的一些示例也包含在此 DZone article 中。

注意:我是 Eclipse Collections 的提交者。

【讨论】:

【参考方案12】:

创建一个新列表并使用addAll()方法添加一个源列表的子列表视图来创建一个新的子列表

List<T> newList = new ArrayList<T>();
newList.addAll(sourceList.subList(startIndex, endIndex));

【讨论】:

【参考方案13】:

使用StreamEx库,可以使用StreamEx.ofSubLists(List&lt;T&gt; source, int length)方法:

返回一个新的 StreamEx,它由具有指定长度的给定源列表的非重叠子列表组成(最后一个子列表可能更短)。

// Assuming you don't actually care that the lists are of type ArrayList
List<List<Integer>> sublists = StreamEx.ofSubLists(result, 10).toList();

// If you actually want them to be of type ArrayList, per your question
List<List<Integer>> sublists = StreamEx.ofSubLists(result, 10).toCollection(ArrayList::new);

【讨论】:

【参考方案14】:

您也可以使用FunctionalJava 库-Listpartition 方法。这个库有自己的集合类型,你可以将它们来回转换为java集合。

import fj.data.List;

java.util.List<String> javaList = Arrays.asList("a", "b", "c", "d" );

List<String> fList = Java.<String>Collection_List().f(javaList);

List<List<String> partitions = fList.partition(2);

【讨论】:

这是将您的列表拆分为 2 个列表还是每个列表 2 个值。例如,如果您的初始列表是 10 个元素,这将产生 2 个 5 个列表或 5 个 2 个列表。 @jDub9 这在问题中是必需的。对于 10 个元素,它返回 5 个 2 个列表。github.com/functionaljava/functionaljava/blob/…【参考方案15】:
import org.apache.commons.collections4.ListUtils;
ArrayList<Integer> mainList = .............;
List<List<Integer>> multipleLists = ListUtils.partition(mainList,100);
int i=1;
for (List<Integer> indexedList : multipleLists)
  System.out.println("Values in List "+i);
  for (Integer value : indexedList)
    System.out.println(value);
i++;

【讨论】:

【参考方案16】:

如果您不想导入 apache 公共库,请尝试以下简单代码:

final static int MAX_ELEMENT = 20;

public static void main(final String[] args) 

    final List<String> list = new ArrayList<String>();

    for (int i = 1; i <= 161; i++) 
        list.add(String.valueOf(i));
        System.out.print("," + String.valueOf(i));
    
    System.out.println("");
    System.out.println("### >>> ");
    final List<List<String>> result = splitList(list, MAX_ELEMENT);

    for (final List<String> entry : result) 
        System.out.println("------------------------");
        for (final String elm : entry) 
            System.out.println(elm);
        
        System.out.println("------------------------");
    



private static List<List<String>> splitList(final List<String> list, final int maxElement) 

    final List<List<String>> result = new ArrayList<List<String>>();

    final int div = list.size() / maxElement;

    System.out.println(div);

    for (int i = 0; i <= div; i++) 

        final int startIndex = i * maxElement;

        if (startIndex >= list.size()) 
            return result;
        

        final int endIndex = (i + 1) * maxElement;

        if (endIndex < list.size()) 
            result.add(list.subList(startIndex, endIndex));
         else 
            result.add(list.subList(startIndex, list.size()));
        

    

    return result;

【讨论】:

@Jaafar:我想要同样的,但是在加载了 20 个元素之后,我需要再次加载接下来的 20 个元素,依此类推。所以请给我建议。 嗨@vasantha 对不起,我没有早点看到你的请求,你做到了吗?【参考方案17】:

只是说清楚,这还需要更多的测试......

public class Splitter 

public static <T> List<List<T>> splitList(List<T> listTobeSplit, int size) 
    List<List<T>> sublists= new LinkedList<>();
    if(listTobeSplit.size()>size) 
    int counter=0;
    boolean lastListadded=false;

    List<T> subList=new LinkedList<>();

    for(T t: listTobeSplit)            
         if (counter==0)                
             subList =new LinkedList<>();
             subList.add(t);
             counter++;
             lastListadded=false;
         
         else if(counter>0 && counter<size-1) 
             subList.add(t);
             counter++;
         
         else 
             lastListadded=true;
             subList.add(t);
             sublists.add(subList);
             counter=0;
                       
    
    if(lastListadded==false)
        sublists.add(subList);      
    
    else 
        sublists.add(listTobeSplit);
    
    log.debug("sublists: "+sublists);
    return sublists;
 

【讨论】:

【参考方案18】:
    **Divide a list to lists of n size**

    import java.util.AbstractList;
    import java.util.ArrayList;
    import java.util.List;

    public final class PartitionUtil<T> extends AbstractList<List<T>> 

        private final List<T> list;
        private final int chunkSize;

        private PartitionUtil(List<T> list, int chunkSize) 
            this.list = new ArrayList<>(list);
            this.chunkSize = chunkSize;
        

        public static <T> PartitionUtil<T> ofSize(List<T> list, int chunkSize) 
            return new PartitionUtil<>(list, chunkSize);
        

        @Override
        public List<T> get(int index) 
            int start = index * chunkSize;
            int end = Math.min(start + chunkSize, list.size());

            if (start > end) 
                throw new IndexOutOfBoundsException("Index " + index + " is out of the list range <0," + (size() - 1) + ">");
            

            return new ArrayList<>(list.subList(start, end));
        

        @Override
        public int size() 
            return (int) Math.ceil((double) list.size() / (double) chunkSize);
        
    





Function call : 
              List<List<String>> containerNumChunks = PartitionUtil.ofSize(list, 999)

更多详情:https://e.printstacktrace.blog/divide-a-list-to-lists-of-n-size-in-Java-8/

【讨论】:

【参考方案19】:

Java8 流,一个表达式,没有其他库(两种解决方案,无需创建不必要的映射):

List<List<Integer>> partitionedList = IntStream.range(0, (list.size()-1)/targetSize+1)
        .mapToObj(i -> list.subList(i*targetSize, Math.min(i*targetSize+targetSize, list.size())))
        .collect(Collectors.toList());

List<List<Integer>> partitionedList2 = IntStream.iterate(0, i -> i < list.size(), i -> i + targetSize)
        .mapToObj(i -> list.subList(i, Math.min(i + targetSize, list.size())))
        .collect(Collectors.toList());

请记住,这些是子列表,因此对原始列表的更改也会影响这些。

如果您不希望它们成为子列表,而是新创建的独立列表,则可以这样修改它们:

List<List<Integer>> partitionedList = IntStream.range(0, (list.size()-1)/targetSize+1)
        .mapToObj(i -> IntStream.range(i*targetSize, Math.min(i*targetSize+targetSize, list.size())).mapToObj(j -> list.get(j)).collect(Collectors.toList()))
        .collect(Collectors.toList());

List<List<Integer>> partitionedList2 = IntStream.iterate(0, i -> i < list.size(), i -> i + targetSize)
        .mapToObj(i -> IntStream.range(i, Math.min(i + targetSize, list.size())).mapToObj(j -> list.get(j)).collect(Collectors.toList()))
        .collect(Collectors.toList());

【讨论】:

【参考方案20】:

您需要知道用于划分列表的块大小。假设您有一个108 entries 的列表,并且您需要25 的块大小。因此你最终会得到5 lists

4 个有 25 entries; 1(第五个)具有8 elements

代码:

public static void main(String[] args) 

        List<Integer> list = new ArrayList<Integer>();
        for (int i=0; i<108; i++)
            list.add(i);
        
        int size= list.size();
        int j=0;
                List< List<Integer> > splittedList = new ArrayList<List<Integer>>()  ;
                List<Integer> tempList = new ArrayList<Integer>();
        for(j=0;j<size;j++)
            tempList.add(list.get(j));
        if((j+1)%25==0)
            // chunk of 25 created and clearing tempList
            splittedList.add(tempList);
            tempList = null;
            //intializing it again for new chunk 
            tempList = new ArrayList<Integer>();
        
        
        if(size%25!=0)
            //adding the remaining enteries 
            splittedList.add(tempList);
        
        for (int k=0;k<splittedList.size(); k++)
            //(k+1) because we started from k=0
            System.out.println("Chunk number: "+(k+1)+" has elements = "+splittedList.get(k).size());
        
    

【讨论】:

【参考方案21】:

假设您希望考虑将列表拆分为多个块的类作为库类。

假设这个类被称为“共享”并且应该是最终的,以确保它不会被扩展。

   import java.util.ArrayList;
   import java.util.Arrays;
   import java.util.List;

public final class Shared 
List<Integer> input;
int portion;

public Shared(int portion, Integer... input) 
    this.setPortion(portion);
    this.setInput(input);


public List<List<Integer>> listToChunks() 
    List<List<Integer>> result = new ArrayList<List<Integer>>();
    int size = this.size();
    int startAt = 0;
    int endAt = this.portion;

    while (endAt <= size) 

        result.add(this.input.subList(startAt, endAt));
        startAt = endAt;
        endAt = (size - endAt < this.portion && size - endAt > 0) ? (this.size()) : (endAt + this.portion);
    

    return result;


public int size() 
    return this.input.size();


public void setInput(Integer... input) 
    if (input != null && input.length > 0)
        this.input = Arrays.asList(input);
    else
        System.out.println("Error 001 : please enter a valid array of integers.");


public void setPortion(int portion) 
    if (portion > 0)
        this.portion = portion;
    else
        System.out.println("Error 002 : please enter a valid positive number.");


接下来,让我们尝试从另一个持有 public static void main(String... args) 的类中执行它

public class exercise 

public static void main(String[] args) 
    Integer[] numbers = 1, 2, 3, 4, 5, 6, 7;
    int portion = 2;
    Shared share = new Shared(portion, numbers);
    System.out.println(share.listToChunks());   


现在,如果您输入一个分区为 2 的整数数组 [1, 2, 3, 4, 5, 6, 7]。 结果将是 [[1, 2], [3, 4], [5, 6], [7]]

【讨论】:

以上是关于Java:如何将 ArrayList 拆分为多个小的 ArrayList?的主要内容,如果未能解决你的问题,请参考以下文章

如何使用JAVA在Android中拆分ArrayList?

Kotlin 在多个索引处将 Arraylist 拆分为多个部分

如何将yaml文件拆分为多个文件?

如何在SSIS中将大型Excel文件拆分为多个小文件?

如何将一个数组拆分成多个固定长度的数组

如何将一个PDF文档拆分为多个文档