可以将Java列表拆分为三个而不循环吗?
给出了一个包含21个元素的Java列表 创建三个新列表的最佳方法是:可以将Java列表拆分为三个而不循环吗?,java,list,Java,List,给出了一个包含21个元素的Java列表 创建三个新列表的最佳方法是: A = 0, 3, 6, ... indexed elements from source B = 1, 4, 7, ... C = 2 ,5, 8, 11, 14, 17, 20 不循环是否可能?您可以编写一个包装类,该类能够在给定倍数(本例中为3)和偏移量(0、1和2)的列表上提供只读“视图”。当要求在特定索引处输入项目时,它必须乘以“倍数”并添加偏移量,然后查看原始列表。(其他操作也是如此。) 不过,循环会更简单。。
A = 0, 3, 6, ... indexed elements from source
B = 1, 4, 7, ...
C = 2 ,5, 8, 11, 14, 17, 20
不循环是否可能?您可以编写一个包装类,该类能够在给定倍数(本例中为3)和偏移量(0、1和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
我在示例中只使用了数组,因为我对它们更有信心,并且不需要看什么就知道它们
我可以问你为什么要避免循环吗?这里有一个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);
}
}
公共类偏移列表扩展了抽象列表{
非公开最终名单代表;
私人最终整数偏移;
私人最终整数倍数;
公共静态偏移列表创建(列表委托、整数偏移、整数倍){
返回新的偏移列表(委托、偏移、多个);
}
专用偏移列表(列表委托、整数偏移、整数倍){
this.delegate=委托;
这个偏移量=偏移量;
这个。多=多;
}
@覆盖公共E-get(int索引){
返回delegate.get(偏移量+(索引*倍数));
}
@重写公共整型大小(){
int offsetToEnd=delegate.size()-offset;
返回(整数)数学单元(偏移结束/(双)倍数);
}
}
示例用法:
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]
List number=//按顺序排列数字0到21
List first=OffsetList.create(数字0,3);
List second=OffsetList.create(数字1,3);
第三个列表=OffsetList.create(数字,2,3);
System.out.println(第一个);//[0, 3, 6, 9, 12, 15, 18, 21]
System.out.println(秒);//[1, 4, 7, 10, 13, 16, 19]
System.out.println(第三个);//[2, 5, 8, 11, 14, 17, 20]
创建每个列表是O(1),因为它们是视图。迭代每个列表是O(n),其中n是实际视图列表的大小,而不是它所基于的完整列表的大小。这假设原始列表是一个随机访问列表。。。这种方法,就像基于索引的迭代一样,对于链表来说是非常低效的。如果你说你已经习惯了函数式编程,我会假设你想要分割列表,因为你想对每个列表做不同的事情。如果是这种情况,我会将过滤逻辑放在
迭代器
级别
您可以使用换行迭代器而不是换行列表
。它可能看起来像这样:
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() {...}
}
}
}
}
下次尝试:)
也可以看到这一点。即使您选择的抽象看起来不像循环,循环也会发生。如果是,我想知道如何发生!如果你只想要三张七张的单子(我想)是可能的。但是你为什么不想循环呢?事实上,你不能硬编码索引吗?我喜欢方便的抽象,而且我习惯于函数式编程。我知道最终需要做一个循环,但我宁愿不去想它。@Annan:“我想抽象掉这个循环”和“我不想有循环”是完全不同的事情。您可以很容易地编写一个实用方法来为您执行循环,这样您就不需要在其他地方考虑它了。@jonskeettrue!这个问题措词不当。虽然我觉得这两个问题都很有趣!我的初衷是在做我自己的之前,看看是否有一个内置的方法来做我想做的事情。@MarkPeters:我不认为
列表。subList
实际上做了我想做的事情,是吗<代码>列表。子列表(0,3)将从原始列表中包装索引0,1,2,而不是根据需要包装索引0,3,6。事实上,我没有注意到这些是索引。删除和添加将使您出错,除非它是只读的view@ratchetfreak:这就是为什么我在回答中说只读视图。即使修改了原始列表,视图也应该没有问题。“当然,它们的大小会改变的。”棘轮怪胎:我想这是预期的行为。您正在按照原始文档中的索引显式定义结果列表。@ColinD您可以提出一种方法。在我知道OP为什么要做他们要求的事情之前,我不明白为什么这不是一个解决方案;如果你重读这个问题,它会说“有可能吗”-我的答案是否定的!谢谢你的否决:((不是)很抱歉,你对我的否决感到失望,但这只是一个糟糕的解决方案。一方面,当问题是关于列表时,它使用数组。另一方面,当它实际上可以使用循环在几行内完成整个操作时,它会手动设置索引值。另外,这显然是可能的,正如Jon的回答中所描述的那样。@Colin首先,你需要我的问题使用了循环的形式,现在你们告诉我,如果我使用循环,我的答案会更好!至于数组,正如我在回答中解释的,我不经常使用列表,所以在没有IDE的情况下,它会减慢我的回答,试图准确地编写语法,这并不是说列表不能很容易地用来代替数组安迪:他说手动展开循环并不比使用循环更可取。你使用的是编译时循环,这只是一个愚蠢的解决办法,因为它会让程序员执行循环。也许科林和我更喜欢实用的解决方案,而不是开玩笑的解决方案。这一点是可以接受的。尽管这不是一个更可取的方法在我看来,这是一个很好的解决方案。我并不知道这是一种循环的形式,而且这是我能想到的最简单、最快捷的方法!虽然我不会称之为开玩笑的解决方案,但我也喜欢实际的解决方案,作为一个例子
for ( ElementType element : filter(elements, 2, 3) ) {
//do something to every third starting with third element
}
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;
}
}
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));
...