2010-11-18 83 views
3

我正在寻找一个具有复合列表实现的开源库。 我需要一个从其他列表中读取其值的列表,并且可以像这样构建:Java复合列表

List list1 = new ArrayList(); 
list1.add("0"); 
List list2 = new LinkedList(); 
list2.add("1"); 
list3.add("2"); 
List list3 = new CompositeList(list1, list2...) 
then:
assertEquals("0", list3.get(0)); 
assertEquals("1", list3.get(1)); 
assertEquals("2", list3.get(2)); 
这个想法是我不需要复制源列表中的所有内容。

快速谷歌没有找到任何东西,我没有看到它在番石榴或公共收藏(我可能忽略了它)。 我现在没有时间正确实施它。

+0

那么你在寻找一个实时视图吗?如果你回去向list1添加内容,你期望什么行为? – 2010-11-18 15:23:35

+0

@标记是的,它必须是活的。 – AmanicA 2010-11-18 15:26:59

+0

可以解释为什么你会想要这个?你最好创建一个包含所有期望元素的新列表(请不要说这是出于性能原因:P) – 2010-11-18 15:27:46

回答

7

CompositeCollectionCommons Collections似乎做你所需要的,即使它没有generified。

+0

我实际上有些害怕,任何图书馆都有这个。它会重新排列任何时候任何基础集合发生更改时返回的元素。当然,除非它复制它们,OP明确不想要的。 – Powerlord 2010-11-18 15:26:18

+5

@ R. Bemrose:有各种各样的装饰器类类的实例,要求你只用*从那时起使用装饰器来正常工作。如果你从'Collections'获得'unmodifiableList',你仍然可以返回并更改你传入的列表,从而也改变了不可修改的列表。如果OP不遵循使用条件,则不能进行担保。现在,这绝对应该*记录在Javadoc ... – 2010-11-18 15:27:50

+0

如果它是一个聚合列表,它本来会很好。 – AmanicA 2010-11-18 21:27:06

11

今天上午我看里面番石榴类似的东西,最后偶然发现Iterables.concat()

您特别要求列表视图,所以这可能不会完全解决您的问题,但这是一个选项要记住。我之前也认为我需要一个Collection/List,但后来我意识到解决我的问题并不是强制性的:我主要是想找出一些东西来连接多个迭代(通过各种Guava过滤/转换获得),在过滤/转换结果之前,最后到dump it into an ImmutableList。如果您只需要迭代结果,则返回Iterable视图也是一个选项。 PS(几年后):现在可以使用Guava的FluentIterable或Java 8流完成这些转换/连接。

1

您可以使用org.apache.commons.collections15.collection.CompositeCollection,它是通用的。

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

+0

由于包名称使它看起来像Apache项目,链接或引用本来就不错。 – madth3 2012-10-26 22:44:33

+0

它在这里:http://search.maven.org/#artifactdetails%7Cnet.sourceforge.collections%7Ccollections-generic%7C4.01%7Cjar – rodche 2013-10-01 03:49:12

0

我们可以构建一个。我使用Guava来实现iterator(),但它不会很难推出自己的产品。

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