一个接一个地重新列出一个列表

时间:2014-02-23 10:31:45

标签: java list optimization collections

我有一个有三种不同类型的列表它们作为组添加到List而不是逐个添加。

这些项目一次添加到列表5中,如下所示: (1,1,1,1,1,2,2,2,2,2,3,3,3,3,3)

现在我想重新排序列表,看起来像这样: (1,2,3,1,2,3 ....)

如何优化此流程?

for (int i = 0; i < list.size(); i++)
     {
            //Reorder the list here
     }

1 个答案:

答案 0 :(得分:1)

只要您的所有群组大小相同,您就可以使用其中一种方法:

import java.util.AbstractList;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class Sorting {

    public static void main(String[] args) {
        final List<Integer> list = Arrays.asList(1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3);
        System.out.println("Input: " + list);
        System.out.println("Solution1 (regroup): " + regroup(list, 3));
        System.out.println("Solution2 (regroup2): " + regroup2(list, 5));
        System.out.println("Solution3 (groupSize constructor): " + new GroupedList<Integer>(list, 5));
        System.out.println("Solution3 (typeCount constructor): " + new GroupedList<Integer>(3, list));
        System.out.println("Demonstration of Solution3 emptyList constructor for groupSize 5");
        final GroupedList<Integer> groupedList = new GroupedList<Integer>(5);
        final List<List<Integer>> oneOfEachType = groupedList.getOneOfEachType();
        System.out.println("Ungrouped: " + groupedList);
        System.out.println("Grouped:" + oneOfEachType);
        // While addAll is shorter code, add also works
        groupedList.addAll(Arrays.asList(11, 12, 13, 14, 15));
        groupedList.addAll(Arrays.asList(21, 22, 23, 24, 25));
        groupedList.add(31);
        groupedList.add(32);
        groupedList.add(33);
        groupedList.add(34);
        groupedList.add(35);
        System.out.println("After adding 3 groups");
        System.out.println("Ungrouped: " + groupedList);
        System.out.println("Grouped:" + oneOfEachType);
        groupedList.addAll(Arrays.asList(41, 42, 43, 44, 45));
        System.out.println("After adding 4th group");
        System.out.println("Ungrouped: " + groupedList);
        System.out.println("Grouped:" + oneOfEachType);
    }

    /**
     * Solution one: returns the reordered list, if you know how many different types are to be handled
     *
     * @param list
     *         input list with equally-sized groups of the same type following each other
     * @param typeCount
     *         count of equally sized groups are in {@code list}
     * @param <T>
     *         type of elements in {@code list}
     * @return new {@link java.util.ArrayList} consisting of the same elements as in {@code list} in the desired order.
     */
    private static <T> List<T> regroup(final List<T> list, final int typeCount) {
        final int groupSize = list.size() / typeCount;
        final ArrayList<T> result = new ArrayList<T>(list.size());
        for (int i = 0; i < groupSize; i++) {
            for (int j = 0; j < typeCount; j++) {
                result.add(list.get(i + j * groupSize));
            }
        }
        return result;
    }


    /**
     * Solution two: returns the reordered list, if you know how many items of each type are added
     *
     * @param list
     *         input list with equally-sized groups of the same type following each other
     * @param groupSize
     *         size of one of the equally sized groups in {@code list}
     * @param <T>
     *         type of elements in {@code list}
     * @return new {@link java.util.ArrayList} consisting of the same elements as in {@code list} in the desired order.
     */
    private static <T> List<T> regroup2(final List<T> list, final int groupSize) {
        final ArrayList<T> result = new ArrayList<T>(list.size());
        for (int i = 0; i < groupSize; i++) {
            for (int j = 0; i + j * groupSize < list.size(); j++) {
                result.add(list.get(i + j * groupSize));
            }
        }
        return result;
    }

    /**
     * Solution three: wrapper class around the original list. This solution reflects changes to the original list
     * immediately and can be used to change the original list if desired
     *
     * @param <T>
     *         type of elements in this list
     */
    public static class GroupedList<T> extends AbstractList<T> {

        private final List<T> list;
        private final int     groupSize;

        /**
         * Empty list, than can be filled with groups of {@code groupSize} elements one group after another.
         */
        public GroupedList(final int groupSize) {
            this.list = new ArrayList<T>();
            this.groupSize = groupSize;
        }

        /**
         * Backed by a list with same-typed groups consisting each of {@code groupSize} elements
         */
        public GroupedList(final List<T> list, final int groupSize) {
            this.list = list;
            this.groupSize = groupSize;
        }


        /**
         * Backed by a list with {@code typeCount} same-typed groups consisting each of the same number of elements
         */
        public GroupedList(final int typeCount, final List<T> list) {
            this.list = list;
            this.groupSize = list.size() / typeCount;
        }

        /**
         * Number of items of the same type. You need to add this many elements at once.
         */
        public int getGroupSize() {
            return groupSize;
        }

        /**
         * Number of different types in each sub-sequence.
         */
        public int getTypeCount() {
            return list.size() / groupSize;
        }

        @Override
        public boolean add(T t) {
            return list.add(t);
        }

        @Override
        public T get(int index) {
            final int realIndex = getRealIndex(index);
            return list.get(realIndex);
        }

        @Override
        public T set(int index, T element) {
            final int realIndex = getRealIndex(index);
            if (realIndex < list.size()) {
                return list.set(realIndex, element);
            } else {
                throw new IndexOutOfBoundsException("Adding to this List-implementation is not possible");
            }
        }

        /**
         * Translate reordered index to index of underlying list
         */
        private int getRealIndex(int index) {
            final int typeCount = getTypeCount();
            if (typeCount * groupSize != list.size()) {
                throw new IllegalStateException("There is an incomplete group. Can't establish list order.");
            }
            final int offsetInGroup = index / typeCount;
            final int groupStart = (index % typeCount) * groupSize;
            return offsetInGroup + groupStart;
        }

        @Override
        public int size() {
            return list.size();
        }

        /**
         * Produce a list of the lists generated by {@link #getOneOfEachType(int)}. The generated list is read-only
         * while the contained lists are writable. Size of this list will always be the same as {@link #getGroupSize()}.
         */
        public List<List<T>> getOneOfEachType() {
            return new AbstractList<List<T>>() {
                @Override
                public List<T> get(int index) {
                    return getOneOfEachType(index);
                }

                @Override
                public int size() {
                    return groupSize;
                }
            };
        }

        /**
         * Get the {@code groupNumber}-th list consisting of on element of each type. You can replace elements of this
         * list and as elements are added to {@link tc.vom.test.with.deps.Sorting.GroupedList} elements will also be
         * visible through the returned list.
         */
        public List<T> getOneOfEachType(final int groupNumber) {
            return new AbstractList<T>() {

                @Override
                public T get(int index) {
                    return list.get(getRealIndex(index));
                }

                @Override
                public T set(int index, T element) {
                    return list.set(getRealIndex(index), element);
                }

                private int getRealIndex(int index) {
                    final int typeCount = getTypeCount();
                    if (index >= typeCount) {
                        throw new IndexOutOfBoundsException();
                    }
                    if (typeCount * groupSize != list.size()) {
                        throw new IllegalStateException("There is an incomplete group. Can't establish list order.");
                    }
                    return index * groupSize + groupNumber;
                }

                @Override
                public int size() {
                    return getTypeCount();
                }
            };
        }
    }
}

使用regroup,您需要知道现在需要多少种类型regroup2才能插入相同类型的数量。

使用GroupedList,您可以围绕现有List创建包装器。您可以按所需顺序迭代GroupedList,只要原始List中的元素数量在迭代期间不发生变化,它就会起作用。您还可以使用getOneOfEachType()迭代各个子组,而无需使用外部计数器 我只实现了add(T)而不是add(int,T),因为转移虚拟订单有点棘手(但可以完成)。摘要列表使用add(T)来实现addAll(Collection<T>),因此这也有效 如果你需要在List之后添加getOneOfEachType我的previous implementation可能会更快,因为typeCount是固定的。通过将getTypeCount()替换为typeCount,可以轻松地将GroupedList - 函数用于旧实现。

两个函数和{{1}}仅在组大小相同时才起作用。