Java: diviser une liste en deux sous-listes?

Quel est le moyen le plus simple, le plus standard et/ou le plus efficace de diviser une liste en deux sous-listes en Java? Il est possible de muter la liste originale, donc aucune copie ne devrait être nécessaire. La signature de la méthode pourrait être

/** 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 retourne une vue sur la liste originale, qui devient invalide si l'original est modifié. Ainsi split ne peut pas utiliser subList à moins qu'il ne dispense également de la référence originale (ou, comme dans Marc Novakowski réponse, utilise subList mais copie immédiatement le résultat).

32
demandé sur Chris Conway 2008-12-19 01:29:37

12 réponses

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

qui utilise des méthodes de mise en œuvre de listes standard et évite toute rotation en boucle. La méthode clear() va également utiliser le removeRange() interne pour la plupart des listes et être beaucoup plus efficace.

52
répondu Lawrence Dol 2014-04-15 22:57:38

vous pouvez utiliser des utilitaires courants, comme bibliothèque 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);

le résultat est une liste de deux listes - pas tout à fait selon vos spécifications, mais vous pouvez facilement vous adapter, si nécessaire.

29
répondu altumano 2012-05-17 11:44:41

Riffing on Marc's solution , cette solution utilise une boucle for qui sauve quelques appels à 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;
}
5
répondu Brandon DuRette 2017-05-23 10:30:58

obtenir le tableau retourné est assez facile en utilisant la méthode de sous-liste, mais il n'y a pas de moyen facile que je connaisse pour supprimer une gamme d'éléments d'une liste.

voilà ce que j'ai:

<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
répondu Marc Novakowski 2008-12-18 22:40:34

j'avais besoin de quelque chose de similaire donc c'est mon implémentation. Il permet à l'appelant de préciser quelle implémentation de la liste doit être retournée:

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

}

et certains cas d'essai:

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

}

3
répondu Matías R 2011-01-27 11:13:49
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++;
    }
  }
}
3
répondu NaAl 2012-06-20 23:55:10

j'utilise le " Apache Commons Collections 4 " de la bibliothèque. Il a une méthode de partition dans la classe ListUtils:

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

cette méthode est adaptée de http://code.google.com/p/guava-libraries /

2
répondu Alberto De Francisco Martín 2015-11-03 09:37:08
<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;
}
1
répondu Joachim Sauer 2008-12-19 12:43:53

une fonction générique pour diviser une liste en une liste de taille spécifique. Ça m'a longtemps manqué dans les 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;
    }
1
répondu Coder by Force 2010-04-26 13:26:43

de la même façon que pour la liste de Marc, nous utiliserons la liste.removeAll () pour supprimer les entrées en double de la deuxième liste. Notez que, à strictement parler, cela ne suit les spécifications que si la liste originale ne contenait pas de doublons: sinon, la liste originale peut être manquante.

<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;
}
0
répondu James 2008-12-19 01:08:18

exemple de code java pour diviser la liste

Liste publique> split(Liste de liste, 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;
}
0
répondu kem 2012-03-18 20:20:16

ma solution:

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

devrait fonctionner:)

0
répondu Xesau 2014-09-30 20:20:23