是否可以将Java列表拆分为三个而不进行循环?

时间:2011-11-12 16:14:00

标签: java list

给定一个包含21个元素的Java List。

使用以下方法创建三个新列表的最佳方法是什么:

A = 0, 3, 6, ... indexed elements from source
B = 1, 4, 7, ... 
C = 2 ,5, 8, 11, 14, 17, 20

没有循环可以吗?

5 个答案:

答案 0 :(得分:6)

可以编写一个包装类,它能够在给定倍数(在这种情况下为3)和偏移量(0,1和2)的列表上提供只读“视图” )。当在特定索引处询问项目时,它必须乘以“倍数”并添加偏移量,然后查看原始列表。 (同样适用于其他操作。)

循环虽然更简单......这里的背景是什么?你真正想要实现的是什么?

答案 1 :(得分:2)

这里是Jon提到的一个例子(当然,你真的不想循环)。这个名字并不是很好......我不确定这样一个好名字是什么。

public class OffsetList<E> extends AbstractList<E> {

  private final List<E> delegate;
  private final int offset;
  private final int multiple;

  public static <E> OffsetList<E> create(List<E> delegate, int offset, int multiple) {
    return new OffsetList<E>(delegate, offset, multiple);
  }

  private OffsetList(List<E> delegate, int offset, int multiple) {
    this.delegate = delegate;
    this.offset = offset;
    this.multiple= multiple;
  }

  @Override public E get(int index) {
    return delegate.get(offset + (index * multiple));
  }

  @Override public int size() {
    int offsetToEnd = delegate.size() - offset;
    return (int) Math.ceil(offsetToEnd / (double) multiple);
  }
}

使用示例:

List<Integer> numbers = // the numbers 0 to 21 in order
List<Integer> first = OffsetList.create(numbers, 0, 3);
List<Integer> second = OffsetList.create(numbers, 1, 3);
List<Integer> third = OffsetList.create(numbers, 2, 3);

System.out.println(first); // [0, 3, 6, 9, 12, 15, 18, 21]
System.out.println(second); // [1, 4, 7, 10, 13, 16, 19]
System.out.println(third); // [2, 5, 8, 11, 14, 17, 20]

创建每个列表是O(1),因为它们是视图。迭代每个列表是O(n),其中n是实际视图列表的大小,而不是它所基于的完整列表的大小。这假设原始列表是随机访问列表......这种方法与基于索引的迭代一样,对于链表而言效率非常低。

答案 2 :(得分:1)

鉴于你说你已经习惯了函数式编程,我会假设你想要分割列表,因为你想要不同的东西。如果是这种情况,我会将过滤逻辑放在Iterator级别。

您可以使用包装 Iterator 而不是包装List。它可能看起来像这样:

public <T> Iterable<T> filter(final Iterable<T> allElements, final int offset, final int multiple) {
    return new Iterable<T> {
        public Iterator<T> iterator() {
            return new Iterator<T> {
                int index = 0;
                Iterator<T> allElementsIt = allElements.iterator();

                public boolean hasNext() {

                    while (allElementsIt.hasNext()) { 
                       if ( isDesiredIndex(index) ) {
                           return true;
                       } else {
                           allElementsIt.next();
                           index++;
                       }
                    }
                    return false;
                }

                private boolean isDesiredIndex(int index) {
                    return (index - offset) % multiple == 0;
                }

                public T next() {
                    if ( hasNext() ) {
                        return allElementsIt.next();
                    } else {
                        throw NoSuchElementException();
                    }
                }

                public void remove() {...}
            }
        }
    }
 }

然后使用它:

for ( ElementType element : filter(elements, 2, 3) ) {
    //do something to every third starting with third element
}

答案 3 :(得分:-1)

接下来尝试:)

class Mod3Comparator implements Comparator<Integer> {
    public int compare(Integer a, Integer b) {
        if (a % 3 < b % 3 || (a % 3 == b % 3 && a < b)) {
            return -1;
        }
        if (a % 3 > b % 3 || (a % 3 == b % 3 && a > b)) {
            return 1;
        }
        return 0;
    }
}

首先根据模数规则对列表进行排序,然后使用Arrays.copyOfRange方法。

Collections.sort(list, new Mod3Comparator());
Integer[] array = new Integer[list.size()]; 
list.toArray(array);
List<Integer> A = Arrays.asList(Arrays.copyOfRange(array, 0, 7));
List<Integer> B = Arrays.asList(Arrays.copyOfRange(array, 7, 14));
...

另见example

答案 4 :(得分:-2)

不幸的是,我无法想到这样做的方式而不假装数组列表正在执行以下操作。

String[] twentyOne = new String[21];

String[] first = new String[3];
first[0] = twentyOne[0];
first[1] = twentyOne[3];
first[2] = twentyOne[6];
//  And so on

String[] second = new String[3];
second[0] = twentyOne[1];
second[1] = twentyOne[4];
second[2] = twentyOne[7];

String[] third = new String[15];
third[0] = twentyOne[2];
// You get the picture

我在示例中只使用了数组,因为我对它们更有信心,并且无需查看内容即可了解它们。

我可以问你为什么要避免循环?