Ignacio Garat
Ignacio Garat

Reputation: 1556

Split larger collection (Collections, Arrays, List) into smaller collections in Java and also keep track of last one returned

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

I am trying to split a bigger collection into smaller collections, depending on the number of items in the original collection. And then return one of the smaller collections every time the get method is called while keeping track of which smaller collection is returned. How can I achieve this?

Upvotes: 20

Views: 44489

Answers (8)

Ahmed Rezk
Ahmed Rezk

Reputation: 301

You can create a separate sublist that is a deep copy of the original list using the ArrayList constructor.

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

Upvotes: 1

charm
charm

Reputation: 1

here is my implementation. hope it helps!

dependencies CollectionUtils and Lists to see: 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;
}

Upvotes: 0

Thufir
Thufir

Reputation: 8487

Maybe I don't understand the question, but this is part of List:

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

Returns a view of the portion of this list between the specified fromIndex, inclusive, and toIndex, exclusive. (If fromIndex and toIndex are equal, the returned list is empty.) The returned list is backed by this list, so non-structural changes in the returned list are reflected in this list, and vice-versa. The returned list supports all of the optional list operations supported by this list.

This method eliminates the need for explicit range operations (of the sort that commonly exist for arrays). Any operation that expects a list can be used as a range operation by passing a subList view instead of a whole list. For example, the following idiom removes a range of elements from a list:

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

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

Upvotes: 44

snupers
snupers

Reputation: 11

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

Upvotes: 1

Kevin Bourrillion
Kevin Bourrillion

Reputation: 40851

This is simple: just use Lists.partition() from Guava. If I understand what you want correctly, it's exactly what it does.

Upvotes: 17

Ignacio Garat
Ignacio Garat

Reputation: 1556

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

Setting the current "run" with the next & previous button actions

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";
}

Upvotes: 4

ColinD
ColinD

Reputation: 110046

I'm not entirely sure what you're asking... do you want to remove the first 4 items from the source Collection before returning them, so that you get the next 4 the next time you call the method? If so, you could just use the Iterator:

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

By doing this, though, you'd be destroying the movie object's collection of comments (unless it returns a copy of that collection each time, in which case the above wouldn't work at all). I'm guessing you're trying to do something like paging, in which case I'd suggest doing something different like partitioning a List of comments with size 4 and keeping track of a current index (the page) in that partition list.

Upvotes: 2

Noam Nevo
Noam Nevo

Reputation: 3081

You can use Vector.remove(collection), example:

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

assuming movie.getCommentCollection() is also a vector

Upvotes: 0

Related Questions