Java:将List拆分为两个子列表?

时间:2008-12-18 22:29:38

标签: java list

在Java中将List拆分为两个子列表的最简单,最标准和/或最有效的方法是什么?改变原始列表是可以的,因此不需要复制。方法签名可以是

/** Split a list into two sublists. The original list will be modified to
 * have size i and will contain exactly the same elements at indices 0 
 * through i-1 as it had originally; the returned list will have size 
 * len-i (where len is the size of the original list before the call) 
 * and will have the same elements at indices 0 through len-(i+1) as 
 * the original list had at indices i through len-1.
 */
<T> List<T> split(List<T> list, int i);

[EDIT] List.subList返回原始列表中的视图,如果修改了原始列表,该视图将无效。因此,split不能使用subList,除非它还省略了原始引用(或者,如在Marc Novakowski的回答中,使用subList但是立即复制结果)。

14 个答案:

答案 0 :(得分:54)

快速半伪代码:

List sub=one.subList(...);
List two=new XxxList(sub);
sub.clear(); // since sub is backed by one, this removes all sub-list items from one

它使用标准的List实现方法,并避免所有在循环中运行。对于大多数列表,clear()方法也将使用内部removeRange()并且效率更高。

答案 1 :(得分:30)

您可以使用常用实用程序,例如Guava库:

import com.google.common.collect.Lists;
import com.google.common.math.IntMath;
import java.math.RoundingMode;

int partitionSize = IntMath.divide(list.size(), 2, RoundingMode.UP);
List<List<T>> partitions = Lists.partition(list, partitionSize);

结果是两个列表的列表 - 不完全符合您的规范,但如果需要,您可以轻松进行调整。

答案 2 :(得分:5)

重复Marc's solution,此解决方案使用for循环来保存对list.size()的一些调用:

<T> List<T> split(List<T> list, int i) {
    List<T> x = new ArrayList<T>(list.subList(i, list.size()));
    // Remove items from end of original list
    for (int j=list.size()-1; j>i; --j)
        list.remove(j);
    return x;
}

答案 3 :(得分:4)

使用subList方法获取返回的数组非常简单,但我知道从List中删除一系列项目并不容易。

这就是我所拥有的:

<T> List<T> split(List<T> list, int i) {
    List<T> x = new ArrayList<T>(list.subList(i, list.size()));
    // Remove items from end of original list
    while (list.size() > i) {
        list.remove(list.size() - 1);
    }
    return x;
}

答案 4 :(得分:4)

我需要类似的东西,所以这是我的实施。它允许调用者指定应返回List的哪个实现:

package com.mrojas.util;

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

public class ListUtils {

/**
 * Splits a list into smaller sublists.
 * The original list remains unmodified and changes on the sublists are not propagated to the original list.
 *
 *
 * @param original
 *            The list to split
 * @param maxListSize
 *            The max amount of element a sublist can hold.
 * @param listImplementation
 *            The implementation of List to be used to create the returned sublists
 * @return A list of sublists
 * @throws IllegalArgumentException
 *             if the argument maxListSize is zero or a negative number
 * @throws NullPointerException
 *             if arguments original or listImplementation are null
 */
public static final <T> List<List<T>> split(final List<T> original, final int maxListSize,
        final Class<? extends List> listImplementation) {
    if (maxListSize <= 0) {
        throw new IllegalArgumentException("maxListSize must be greater than zero");
    }

    final T[] elements = (T[]) original.toArray();
    final int maxChunks = (int) Math.ceil(elements.length / (double) maxListSize);

    final List<List<T>> lists = new ArrayList<List<T>>(maxChunks);
    for (int i = 0; i < maxChunks; i++) {
        final int from = i * maxListSize;
        final int to = Math.min(from + maxListSize, elements.length);
        final T[] range = Arrays.copyOfRange(elements, from, to);

        lists.add(createSublist(range, listImplementation));
    }

    return lists;
}

/**
 * Splits a list into smaller sublists. The sublists are of type ArrayList.
 * The original list remains unmodified and changes on the sublists are not propagated to the original list.
 *
 *
 * @param original
 *            The list to split
 * @param maxListSize
 *            The max amount of element a sublist can hold.
 * @return A list of sublists
 */
public static final <T> List<List<T>> split(final List<T> original, final int maxListSize) {
    return split(original, maxListSize, ArrayList.class);
}

private static <T> List<T> createSublist(final T[] elements, final Class<? extends List> listImplementation) {
    List<T> sublist;
    final List<T> asList = Arrays.asList(elements);
    try {
        sublist = listImplementation.newInstance();
        sublist.addAll(asList);
    } catch (final InstantiationException e) {
        sublist = asList;
    } catch (final IllegalAccessException e) {
        sublist = asList;
    }

    return sublist;
}

}

以及一些测试用例:

package com.mrojas.util;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;

import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;

import org.junit.Test;

public class ListUtilsTest {

@Test
public void evenSplitTest() {
    final List<List<Object>> sublists = ListUtils.split(getPopulatedList(10), 2, LinkedList.class);
    assertEquals(5, sublists.size());
    for (final List<Object> sublist : sublists) {
        assertEquals(2, sublist.size());
        assertTrue(sublist instanceof LinkedList<?>);
    }
}

@Test
public void unevenSplitTest() {
    final List<List<Object>> sublists = ListUtils.split(getPopulatedList(10), 3, LinkedList.class);
    assertEquals(4, sublists.size());

    assertEquals(3, sublists.get(0).size());
    assertEquals(3, sublists.get(1).size());
    assertEquals(3, sublists.get(2).size());
    assertEquals(1, sublists.get(3).size());
}

@Test
public void greaterThanSizeSplitTest() {
    final List<List<Object>> sublists = ListUtils.split(getPopulatedList(10), 20, LinkedList.class);
    assertEquals(1, sublists.size());
    assertEquals(10, sublists.get(0).size());
}

@Test
public void emptyListSplitTest() {
    final List<List<Object>> sublists = ListUtils.split(Collections.emptyList(), 10, LinkedList.class);
    assertEquals(0, sublists.size());
}

@Test(expected=IllegalArgumentException.class)
public void negativeChunkSizeTest() {
    ListUtils.split(getPopulatedList(5), -10, LinkedList.class);
}

@Test
public void invalidClassTest() {
    final List<List<Object>> sublists = ListUtils.split(getPopulatedList(10), 2, LinkedList.class);
    assertEquals(5, sublists.size());
    for (final List<Object> sublist : sublists) {
        assertEquals(2, sublist.size());
        assertTrue(sublist instanceof LinkedList<?>);
    }
}

private List<Object> getPopulatedList(final int size) {
    final List<Object> list = new ArrayList<Object>(10);
    for (int i = 0; i < 10; i++) {
        list.add(new Object());
    }

    return list;
}

}

答案 5 :(得分:3)

import java.util.Collection;

public class CollectionUtils {

  /**
   * Will split the passed collection so that the size of the new collections
   * is not greater than maxSize
   * @param t
   * @param maxSize
   * @return a List containing splitted collections
   */

  @SuppressWarnings("unchecked")
  public static <T> List<Collection<T>>split(Collection<T> t, int maxSize) {
    int counter = 0;
    List<Collection<T>> ret = new LinkedList<Collection<T>>();
    Iterator<T>itr = t.iterator();
    try {
      Collection<T> tmp = t.getClass().newInstance();
      ret.add(tmp);
      while(itr.hasNext()) {
        tmp.add(itr.next());
        counter++;
        if(counter>=maxSize && itr.hasNext()) {
          tmp = t.getClass().newInstance();
          ret.add(tmp);
          counter=0;
        }
      }
    } catch(Throwable e) {
      Logger.getLogger(CollectionUtils.class).error("There was an error spliting "+t.getClass(),e);
    }
    return ret;
  }

}

// JUnit test cases

import java.util.ArrayList;

/**
 *
 * $Change$
 * @version $Revision$
 * Last modified date & time $DateTime$
 */
public class CollectionUtilsTest {

  @Test
  public void testSplitList() {
    List<Integer>test = new ArrayList<Integer>(100);
    for (int i=1;i<101;i++) {
      test.add(i);
    }
    List<Collection<Integer>> tests = CollectionUtils.split(test, 10);
    Assert.assertEquals("Size mismatch", 10,tests.size());

    TreeSet<Integer> tmp = new TreeSet<Integer>();
    for(Collection<Integer> cs:tests) {
      for(Integer i:cs) {
        Assert.assertFalse("Duplicated item found "+i,tmp.contains(i));
        tmp.add(i);
      }
      System.out.println(cs);
    }
    int why = 1;
    for(Integer i:tmp) {
      Assert.assertEquals("Not all items are in the collection ",why,i.intValue());
      why++;
    }
  }
  @Test
  public void testSplitSet() {
    TreeSet<Integer>test = new TreeSet<Integer>();
    for (int i=1;i<112;i++) {
      test.add(i);
    }
    List<Collection<Integer>> tests = CollectionUtils.split(test, 10);
    Assert.assertEquals("Size mismatch", 12,tests.size());

    TreeSet<Integer> tmp = new TreeSet<Integer>();
    int cI = 0;
    for(Collection<Integer> cs:tests) {
      for(Integer i:cs) {
        Assert.assertFalse("Duplicated item found "+i,tmp.contains(i));
        tmp.add(i);
      }
//      if(cI>10) {
        System.out.println(cs);
//      }
      cI++;
    }
    int why = 1;
    for(Integer i:tmp) {

      Assert.assertEquals("Not all items are in the collection ",why,i.intValue());
      why++;
    }
  }
}

答案 6 :(得分:3)

我使用“Apache Commons Collections 4”库。它在ListUtils类中有一个分区方法:

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

此方法改编自http://code.google.com/p/guava-libraries/

答案 7 :(得分:1)

<T> List<T> split(List<T> list, int i) {
   List<T> secondPart = list.sublist(i, list.size());
   List<T> returnValue = new ArrayList<T>(secondPart());
   secondPart.clear(),
   return returnValue;
}

答案 8 :(得分:1)

将列表拆分为特定大小列表的通用函数。我在java集合中长期缺少这一点。

private List<List<T>> splitList(List<T> list, int maxListSize) {
        List<List<T>> splittedList = new ArrayList<List<T>>();
        int itemsRemaining = list.size();
        int start = 0;

        while (itemsRemaining != 0) {
            int end = itemsRemaining >= maxListSize ? (start + maxListSize) : itemsRemaining;

            splittedList.add(list.subList(start, end));

            int sizeOfFinalList = end - start;
            itemsRemaining = itemsRemaining - sizeOfFinalList;
            start = start + sizeOfFinalList;
        }

        return splittedList;
    }

答案 9 :(得分:0)

同样地从Marc的列表中删除,我们将使用List.removeAll()从第二个列表中删除重复的条目。请注意,严格来说,如果原始列表中没有重复项目,则仅遵循规范:否则,原始列表可能缺少项目。

<T> List<T> split(List<T> list, int i) {
        List<T> x = new ArrayList<T>(list.subList(i, list.size()));
        // Remove items from end of original list
        list.removeAll(x);
        return x;
}

答案 10 :(得分:0)

示例java代码拆分列表

公开名单&gt; split(列表列表,int i){

    List<List<Long>> out = new ArrayList<List<Long>>();

    int size = list.size();

    int number = size/i;
    int remain = size % i; 
    if(remain != 0){
        number++;
    }

    for(int j=0; j < number; j++){
        int start  = j * i;
        int end =  start+ i;
        if(end > list.size()){
            end = list.size();
        }
        out.add(list.subList(start, end));
    }

    return out;
}

答案 11 :(得分:0)

我的解决方案:

List<X> listToSplit = new ArrayList<X>();

List<X> list1 = new ArrayList<X>();
List<X> list2 = new ArrayList<X>();

for (X entry : listToSplit)
{
    if (list1.size () > list2.size ())
        list2.add (entry);
    else
        list1.add( entry );
}

应该工作:)

答案 12 :(得分:0)

//Here is my list
    ArrayList<T> items=new ArrayList<T>();
    Integer startIndex = 0;
            int j = 0;
            for (; j < items.size() - 1; j++) {//always start with next index not again 0
                for (int i = 0; i < 4; i++) { // divide into equal part with 4 item
                    startIndex = startIndex + 1;
                    j = startIndex;
                }
            }

答案 13 :(得分:0)

使用流的解决方案,对每个项目使用切换/翻转布尔值进行分区:

print(df.iloc[2,2:,2:4].min(axis=1))

您最终得到一个包含两个条目的映射,键是Collection<String> big = ...; AtomicBoolean switcheroo = new AtomicBoolean(); Map<Boolean, List<String>> subLists = big.stream() .collect(Collectors.partitioningBy(o -> switcheroo.getAndSet(!switcheroo.get()))); true,值是子列表。

这并不能完全回答原始问题,但是您可以使用每次递增的false而不是AtomicInteger