Java:将一个列表分成两个子列表?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/379551/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Java: split a List into two sub-Lists?
提问by Chris Conway
What's the simplest, most standard, and/or most efficient way to split a List into two sub-Lists in Java? It's OK to mutate the original List, so no copying should be necessary. The method signature could be
在 Java 中将 List 拆分为两个子 List 的最简单、最标准和/或最有效的方法是什么?对原始 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
returns a view on the original list, which becomes invalid if the original is modified. So split
can't use subList
unless it also dispenses with the original reference (or, as in Marc Novakowski's answer, uses subList
but immediately copies the result).
[EDIT]List.subList
返回原始列表上的视图,如果修改原始列表,则该视图无效。所以split
不能使用,subList
除非它也省去了原始参考(或者,如 Marc Novakowski 的回答,使用subList
但立即复制结果)。
采纳答案by Lawrence Dol
Quick semi-pseudo code:
快速半伪代码:
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
That uses standard List implementation methods and avoids all the running around in loops. The clear() method is also going to use the internal removeRange()
for most lists and be much more efficient.
这使用标准 List 实现方法并避免在循环中运行。clear() 方法还将removeRange()
对大多数列表使用内部方法,并且效率更高。
回答by Marc Novakowski
Getting the returned array is pretty easy using the subList method, but there's no easy way that I know of to remove a range of items from a List.
使用 subList 方法获取返回的数组非常容易,但我知道没有简单的方法可以从 List 中删除一系列项目。
Here's what I have:
这是我所拥有的:
<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;
}
回答by Brandon DuRette
Riffing on Marc's solution, this solution uses a for
loop that saves some calls to list.size()
:
借鉴Marc 的解决方案,该解决方案使用一个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;
}
回答by James
Likewise cribbing off of Marc's list, we'll use List.removeAll() to remove the duplicate entries from the second list. Note that, strictly speaking, this only follows the specs if the original list contained no duplicate items: otherwise, the original list may be missing items.
同样从 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;
}
回答by Joachim Sauer
<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;
}
回答by Coder by Force
A generic function to split a list to a list of list of specific size. I was missing this for long in java collections.
将列表拆分为特定大小列表的通用函数。我在 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;
}
回答by Matías R
I needed something similar so this is my implementation. It allows the caller to specify which implementation of List should be returned:
我需要类似的东西,所以这是我的实现。它允许调用者指定应该返回 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;
}
}
}
And some test cases:
还有一些测试用例:
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;
}
}
}
回答by kem
sample java code to split List
用于拆分列表的示例 java 代码
public List<List<Long>> split(List<Long> list, 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;
}
回答by altumano
You can use common utilities, like Guava library:
您可以使用常见的实用程序,例如 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);
The result is a list of two lists - not quite by your spec, but you can easily adapt, if needed.
结果是两个列表的列表 - 不完全符合您的规范,但如果需要,您可以轻松适应。
回答by NaAl
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++;
}
}
}