Java: разделить список на два подсписка?

Какой самый простой, самый стандартный и / или самый эффективный способ разбить список на два подсписка в Java? Это нормально, чтобы изменить исходный список, поэтому не нужно копировать. Подпись метода может быть

/** 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);

[РЕДАКТИРОВАТЬ]List.subList возвращает представление в исходном списке, которое становится недействительным, если оригинал изменен. Такsplit не может использоватьsubList если он также не обходится без оригинальной ссылки (или, как в ответе Марка Новаковского, используетsubList но сразу копирует результат).

 Chris Conway19 дек. 2008 г., 15:53
Хемаль, наверное. Так что дайте мне самое простое и самое стандартное.
 Steve Kuo19 дек. 2008 г., 03:18
Ваш комментарий должен начинаться с "/ **", так как это комментарий метода.
 Joachim Sauer22 дек. 2008 г., 16:47
@Hemal: к счастью, с subList () каждая реализация списка может делать то, что быстрее.
 Miserable Variable19 дек. 2008 г., 02:07
Разве «самый эффективный» не будет зависеть от конкретного типа Списка?

Ответы на вопрос(13)

Я используюКоллекции Apache Commons 4"библиотека. Имеет метод разбиения в классе ListUtils:

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

Этот метод адаптирован изhttp://code.google.com/p/guava-libraries/

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

Вы можете использовать общие утилиты, такие как библиотека 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);

В результате получается список из двух списков - не совсем по вашей спецификации, но вы можете легко адаптировать его при необходимости.

 PaulBGD22 нояб. 2013 г., 02:19
Из-за того, что я использовал API с гуавой, это был лучший ответ.
<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;
}
 Marc Novakowski19 дек. 2008 г., 19:25
Хороший способ очистить конец исходного списка без использования цикла for, +1

Пример кода Java для разделения списка

общедоступный список> 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;
}
 Lawrence Dol16 апр. 2014 г., 01:00
Вопросы проситдва подсписки разделены по индексуiнеn списки длиныi.
Решение Вопроса

Быстрый полупсевдокод:

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() для большинства списков и быть гораздо более эффективным.

 Junchen Liu04 февр. 2015 г., 16:08
list.subList (first, Math.min (list.size (), first + pagesize));
 Lawrence Dol04 февр. 2015 г., 20:19
@shanyangqu: Нет, поскольку подсписок поддерживается оригиналом и не удаляет элементы в подсписке из оригинала. В основном подсписок это простоПосмотреть в больший список.

Riffing onРешение Маркаэто решение использует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;
}

Универсальная функция для разделения списка на список определенного размера. Я скучал по этому долго в коллекциях 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;
    }
 user35008923 февр. 2011 г., 16:16
В вашем коде есть ошибка, первая строка блока while должна быть такой:int end = itemsRemaining >= maxListSize ? (start + maxListSize) : **(start + itemsRemaining)**;

Аналогичным образом вычеркивая список Марка, мы будем использовать 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;
}
 Brandon DuRette19 дек. 2008 г., 07:59
Я думаю, что это решение не работает в случае, когда элементы .equals () появляются в обоих разделах.
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++;
    }
  }
}
 NaAl21 июн. 2012 г., 01:57
некоторые тестовые случаи:

Мне нужно что-то подобное, так что это моя реализация. Это позволяет вызывающей стороне указать, какая реализация 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;
}

}

Мое решение:

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

Должно сработать :)

Получить возвращенный массив довольно просто, используя метод 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;
}
 Joachim Sauer19 дек. 2008 г., 14:47
.subList (i, list.Size ()). clear () должен удалить элементы, содержащиеся в подсписке, из базового списка (как упомянуто в JavaDoc подсписка). Смотрите мой ответ ниже для примера.
 Marc Novakowski18 дек. 2008 г., 23:41
Одно уточнение - я создаю новый ArrayList, потому что список, возвращаемый subList, поддерживается исходным списком, и, поскольку мы модифицируем его позже, он может испортить возвращаемый список.
 Dan Vinton18 дек. 2008 г., 23:59
Совершенно верно. Спасибо за указание на ошибки в моей (теперь удаленной) попытке - это то, что я получаю за публикацию в полусне ...

Ваш ответ на вопрос