Java Composite List

I am looking for an open source library that has an implementation of a composite list. I need a list that reads its values ​​from some other lists and can be built something like this:

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));
The idea is that I do not need to copy all of the source lists.

Fast google did not find anything, I did not see it in the collections of Guava or commons (maybe I missed it). Now I do not have time to use it correctly.

+3
source share
5 answers

The CompositeCollection from Collection Collections does what you need, even if it has not been created.

+7

- , , Iterables.concat().

"", , , .

, /, , : -, ( / Guava), / , , ImmutableList. Iterable , .

PS ( ): / Guava FluentIterable Java 8.

+11
+1
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 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());
    }
}
0

Source: https://habr.com/ru/post/1775663/


All Articles