2010-11-18 31 views
3

Je suis à la recherche d'une bibliothèque opensource qui a une implémentation d'une liste composite. J'ai besoin d'une liste qui lit ses valeurs à partir d'autres listes et qui peut être construite comme ceci: Java Composite List

List list1 = new ArrayList(); 
list1.add("0"); 
List list2 = new LinkedList(); 
list2.add("1"); 
list3.add("2"); 
List list3 = new CompositeList(list1, list2...) 
puis:
assertEquals("0", list3.get(0)); 
assertEquals("1", list3.get(1)); 
assertEquals("2", list3.get(2)); 
L'idée est que je n'ai pas besoin de copier tout depuis les listes sources. Un google rapide n'a rien trouvé, je ne l'ai pas vu dans les collections de goyave ou de communes (je l'ai peut-être oublié). Je n'ai pas vraiment le temps de l'implémenter correctement maintenant.

+0

Vous êtes à la recherche d'une vue en direct? Quel comportement attendez-vous si vous revenez ajouter quelque chose à list1? –

+0

@Mark oui il doit être en direct. – AmanicA

+0

Pourrait expliquer pourquoi vous voudriez cela? Vous feriez mieux de créer une nouvelle liste qui contient tous les éléments souhaités (veuillez ne pas dire que c'est pour des raisons de performance: P) –

Répondre

7

CompositeCollection de Commons Collections semble faire ce que vous avez besoin, même si elle n'est pas générée.

+0

Je suis en fait un peu horrifié que n'importe quelle bibliothèque a ceci. Il réorganiserait les éléments qu'il retourne chaque fois que l'une des collections sous-jacentes change. A moins, bien sûr, de les copier, ce que le PO ne veut pas expressément. – Powerlord

+5

@R. Bemrose: Il existe toutes sortes d'exemples de classes de type décorateur qui vous obligent à n'utiliser que le décorateur pour que cela fonctionne correctement. Si vous obtenez un 'unmodifiableList' de' Collections', vous pouvez toujours revenir en arrière et modifier la liste que vous avez transmise, changeant ainsi le non modifiable. Les garanties ne peuvent être faites si le PO ne respecte pas les conditions d'utilisation. Maintenant, cela devrait certainement être * documenté * dans le Javadoc ... –

+0

cela aurait été bien si c'était une liste générée .. – AmanicA

11

que je recherchais l'intérieur Goyave pour quelque chose de semblable ce matin, et finalement trébuché sur Iterables.concat().

Vous avez demandé spécifiquement une vue Liste, cela ne résout peut-être pas exactement votre problème, mais c'est une option à garder à l'esprit. J'ai aussi pensé que j'avais besoin d'une collection/liste au début, mais j'ai réalisé plus tard qu'il n'était pas obligatoire de résoudre mon problème: je cherchais principalement quelque chose pour concaténer plusieurs itérations (obtenues par divers filtrages/transformations de goyave), avant de filtrer/transformer le résultat, pour finalement dump it into an ImmutableList. Le retour de la vue Iterable est également une option, si vous avez seulement besoin d'itérer sur le résultat. PS (quelques années plus tard): ces transformations/concaténations peuvent maintenant être effectuées en utilisant les flux FluentIterable de Guava ou Java 8 aussi.

1

Vous pouvez utiliser org.apache.commons.collections15.collection.CompositeCollection, et c'est générique.

Voir http://search.maven.org/#artifactdetails%7Cnet.sourceforge.collections%7Ccollections-generic%7C4.01%7Cjar

+0

Un lien ou une référence aurait été sympa puisque le nom du paquet le fait ressembler à un projet Apache. – madth3

+0

C'est ici: http://search.maven.org/#artifactdetails%7Cnet.sourceforge.collections%7Ccollections-generic%7C4.01%7Cjar – rodche

0

Nous pouvons construire un. J'utilise Guava pour la mise en œuvre iterator() mais il ne serait pas difficile de rouler les vôtres.

/** 
* A list composed of zero to many child lists. Additions occur in the first 
* acceptable list: if an insertion is attempted at an index that lies on a break 
* between lists, the insert occurs in the first list. Modifications are undefined 
* if list of lists has no elements. 
* @param <T> Type of element stored in list. 
*/ 
public class CompositeList<T> extends AbstractList<T> { 
// member variables --------------------------------------------------------------- 
    private Collection<List<T>> mLists; 

// constructors ------------------------------------------------------------------- 
    public CompositeList(Collection<List<T>> pLists) {mLists = pLists;} 

// methods ------------------------------------------------------------------------ 
    /** Sum of sizes of component lists. */ 
    public int size() {return mLists.stream().mapToInt(Collection::size).sum();} 

    @Override public T get(int pIdx) { 
     final Map.Entry<List<T>,Integer> m = findIndex(pIdx); 
     return m.getKey().get(m.getValue()); 
    } 

    /** 
    * If add could occur at end of one list or beginning of the next, the former 
    * behavior is guaranteed. 
    */ 
    @Override public void add(int pIdx, T pElement) { 
     if (pIdx == 0) { 
      mLists.iterator().next().add(0, pElement); 
     } else { 
      // find prior object 
      final Map.Entry<List<T>,Integer> m = findIndex(pIdx - 1); 
      m.getKey().add(m.getValue() + 1, pElement); 
     } 
    } 

    @Override public T remove(int pIdx) { 
     final Map.Entry<List<T>,Integer> m = findIndex(pIdx); 

     // don't auto-box because remove(Object) and remove(int) can be confused 
     return m.getKey().remove(m.getValue().intValue()); 
    } 

    @Override public T set(int pIdx, T pElement) { 
     final Map.Entry<List<T>,Integer> m = findIndex(pIdx); 
     return m.getKey().set(m.getValue(), pElement); 
    } 

    /** More efficient than superclass implementation. */ 
    @Override public Iterator<T> iterator() { 
     return Iterators.concat(
      Collections2.transform(mLists, Collection::iterator).iterator() 
     ); 
    } 

    @Override public void clear() {mLists.forEach(Collection::clear);} 

    /** 
    * Identify list and index that composite index refers to. For 
    * [A], [], [], [B, C]; composite index 1 would return the fourth list 
    * mapped to the number 0. 
    */ 
    private Map.Entry<List<T>,Integer> findIndex(int pCompositeIdx) { 
     // composite index of list's starting point 
     int listStart = 0; 
     for (final List<T> list : mLists) { 
      if (listStart + list.size() > pCompositeIdx) { 
       return new AbstractMap.SimpleImmutableEntry<>(
        list, pCompositeIdx - listStart 
       ); 
      } 
      listStart += list.size(); 
     } 
     throw new IndexOutOfBoundsException(pCompositeIdx + " >= " + size()); 
    } 
}