【问题标题】:Split larger collection (Collections, Arrays, List) into smaller collections in Java and also keep track of last one returned在 Java 中将较大的集合(集合、数组、列表)拆分为较小的集合,并跟踪最后一个返回的集合
【发布时间】:2025-12-26 10:55:16
【问题描述】:
public Collection<Comment> getCommentCollection() {
   commentCollection = movie.getCommentCollection();       
   return split((List<Comment>) commentCollection, 4);
}

public Collection<Comment> split(List<Comment> list, int size){

     int numBatches = (list.size() / size) + 1;
     Collection[] batches = new Collection[numBatches];
     Collection<Comment> set = commentCollection;

     for(int index = 0; index < numBatches; index++) {
         int count = index + 1;
         int fromIndex = Math.max(((count - 1) * size), 0);
         int toIndex = Math.min((count * size), list.size());
         batches[index] = list.subList(fromIndex, toIndex);
         set = batches[index];
     }

     return set;
 }

我正在尝试将较大的集合拆分为较小的集合,具体取决于原始集合中的项目数。然后在每次调用 get 方法时返回较小的集合之一,同时跟踪返回的是哪个较小的集合。我怎样才能做到这一点?

【问题讨论】:

  • ArrayList 优于 Vector。
  • 没有与问题的直接链接,但您应该使用 Vector (ArrayList?) 以外的其他东西 => *.com/questions/300519/…

标签: java arrays list collections


【解决方案1】:

您可以使用 ArrayList 构造函数创建一个单独的子列表,它是原始列表的深层副本。

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

class Scratch {
    public static void main(String[] args) {
        final List<String> parent = new ArrayList<>();
        parent.add("One");
        parent.add("Two");
        parent.add("Three");

        // using the ArrayList constructor here
        final List<String> copy = new ArrayList<>(parent.subList(0, 2));
   
        // modifying the new list doesn't affect the original
        copy.remove(0);

        // outputs:
        // parent: [One, Two, Three]
        // copy:   [Two]
        System.out.println("parent: " + parent);
        System.out.println("copy:   " + copy);
    }
}

【讨论】:

    【解决方案2】:

    这是我的实现。希望有帮助!

    dependencies CollectionUtilsLists 查看: https://mvnrepository.com/artifact/org.apache.commons/commons-lang3/

    /**
     * efficient collection partition
     *
     * @param baseCollection base collection to split
     * @param maxSize max element size of each sublist returned
     * @param balancing whether each of sublists returned needs size balancing
     * @return list of sublists, whose order bases on the base collection's iterator implementation
     * @since 2020/03/12
     */
    public static <T> List<List<T>> partition(final Collection<T> baseCollection, int maxSize, boolean balancing) {
    
        if (CollectionUtils.isEmpty(baseCollection)) {
            return Collections.emptyList();
        }
    
        int size = baseCollection.size() % maxSize == 0 ? baseCollection.size()/maxSize : baseCollection.size()/maxSize+1;
        if (balancing) {
            maxSize = baseCollection.size() % size == 0 ? baseCollection.size()/size : baseCollection.size()/size+1;
        }
        int fullElementSize = baseCollection.size() % size == 0 ? size : baseCollection.size() % size;
    
        List<List<T>> result = Lists.newArrayListWithExpectedSize(size);
        Iterator<T> it = baseCollection.iterator();
        for (int i = 0; i < size; i++) {
            if (balancing && i == fullElementSize) {
                maxSize--;
            }
            maxSize = Math.min(maxSize, baseCollection.size()-i*maxSize);
    
            List<T> subList = Lists.newArrayListWithExpectedSize(maxSize);
            for (int i1 = 0; i1 < maxSize; i1++) {
                if (it.hasNext()) {
                    subList.add(it.next());
                } else {
                    break;
                }
            }
            result.add(subList);
        }
    
        return result;
    }
    

    【讨论】:

      【解决方案3】:

      也许我不明白这个问题,但这是列表的一部分:

      List<E> subList(int fromIndex, int toIndex)
      

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

      此方法无需显式范围操作(通常存在于数组中的那种)。任何需要列表的操作都可以通过传递 subList 视图而不是整个列表来用作范围操作。例如,以下成语从列表中删除一系列元素:

      list.subList(from, to).clear();

      docs.oracle.com/javase/1.5.0/docs/api/java/util/List.html

      【讨论】:

      • 这太令人兴奋了,我已经使用集合多年了,但我从未注意到这种方法!
      【解决方案4】:
      public static <E extends Object> List<List<E>> split(Collection<E> input, int size) {\n
          List<List<E>> master = new ArrayList<List<E>>();
          if (input != null && input.size() > 0) {
              List<E> col = new ArrayList<E>(input);
              boolean done = false;
              int startIndex = 0;
              int endIndex = col.size() > size ? size : col.size();
              while (!done) {
                  master.add(col.subList(startIndex, endIndex));
                  if (endIndex == col.size()) {
                      done = true;
                  }
                  else {
                      startIndex = endIndex;
                      endIndex = col.size() > (endIndex + size) ? (endIndex + size) : col.size();
                  }
              }
          }
          return master;
      }
      

      【讨论】:

      • 请解释你的答案,而不仅仅是给出答案。
      【解决方案5】:

      这很简单:只需使用来自 Guava 的 Lists.partition()。如果我正确理解您想要什么,那就是它的功能。

      【讨论】:

        【解决方案6】:
        private int runs = 0;
        
        public void setRunsOneMore() {
            runs++;
        }
        
            public void setRunsOneLess() {
            runs--;
        }
        
        public Collection<Comment> getCommentCollection() {
            commentCollection = movie.getCommentCollection();
            Collection[] com = split((List<Comment>) commentCollection,4);
            try{
                return com[runs];
             } catch(ArrayIndexOutOfBoundsException e) {
               runs = 0;
              }
            return com[runs];
        }
        
        public Collection[] split(List<Comment> list, int size){
        
             int numBatches = (list.size() / size) + 1;
             Collection[] batches = new Collection[numBatches];
             Collection<Comment> set = commentCollection;
        
             for(int index = 0; index < numBatches; index++) {
                 int count = index + 1;
                 int fromIndex = Math.max(((count - 1) * size), 0);
                 int toIndex = Math.min((count * size), list.size());
                 batches[index] = list.subList(fromIndex, toIndex);
             }
        
             return batches;
         }
        

        使用下一个和上一个按钮操作设置当前“运行”

        public String userNext() {
            userReset(false);
            getUserPagingInfo().nextPage();
            movieController.setRunsOneMore();
            return "user_movie_detail";
        }
        
        public String userPrev() {
            userReset(false);
            getUserPagingInfo().previousPage();
            movieController.setRunsOneLess();
            return "user_movie_detail";
        }
        

        【讨论】:

          【解决方案7】:

          我不完全确定您在问什么...您是否要在返回它们之前从源 Collection 中删除前 4 个项目,以便下次调用该方法时获得下一个 4 ?如果是这样,您可以使用Iterator

          Iterator<Comment> iter = commentCollection.iterator();
          while (iter.hasNext() && group.size() < 4) {
            group.add(iter.next());
            iter.remove();
          }
          

          但是,这样做会破坏movie 对象的 cmets 集合(除非它每次都返回该集合的副本,在这种情况下,上述方法根本不起作用)。我猜你正在尝试做一些类似分页的事情,在这种情况下,我建议做一些不同的事情,比如 partitioning 一个 List 大小为 4 的 cmets 并跟踪其中的当前索引(页面)分区列表。

          【讨论】:

          • 那会怎样?我从来没有用户分区,你能提供一个简单的例子吗?
          【解决方案8】:

          可以使用 Vector.remove(collection),例如:

          public Collection<Comment> getCommentCollection() {
              commentCollection = movie.getCommentCollection();
              Vector<Comment> group = new Vector<Comment>();
              for (Comment com:commentCollection){
                  group.add(com);
              if(group.size() == 4){
                  break;
              }
              }
              movie.getCommentCollection().remove(commentCollection);
              return commentCollection;
          }
          

          假设 movie.getCommentCollection() 也是一个向量

          【讨论】: