Tra*_*ebb 32 java iteration foreach
我继承了一大堆代码,它们广泛使用并行数组来存储键/值对.实际上这样做是有意义的,但是编写循环遍历这些值有点尴尬.我真的很喜欢新的Java foreach构造,但似乎没有办法使用它来迭代并行列表.
通过正常for循环,我可以轻松完成:
for (int i = 0; i < list1.length; ++i) {
doStuff(list1[i]);
doStuff(list2[i]);
}
Run Code Online (Sandbox Code Playgroud)
但在我看来,这不是语义上的纯粹,因为我们没有检查list2迭代期间的界限.是否有一些类似于for-each的聪明语法可用于并行列表?
Isa*_*ett 23
我会用Map自己的.但是,如果您认为一对数组在您的情况下是有意义的,那么采用两个数组并返回Iterable包装器的实用程序方法怎么样?
概念:
for (Pair<K,V> p : wrap(list1, list2)) {
doStuff(p.getKey());
doStuff(p.getValue());
}
Run Code Online (Sandbox Code Playgroud)
该Iterable<Pair<K,V>>包装将隐藏边界检查.
Tik*_*vis 11
从增强型for循环的官方Oracle页面:
最后,它不适用于必须并行迭代多个集合的循环.这些缺点是设计师所熟知的,他们有意识地决定采用干净,简单的结构来覆盖绝大多数情况.
基本上,你最好使用正常的for循环.
如果你使用这些数组对来模拟Map,你总是可以编写一个用两个数组实现Map接口的类; 这可以让你抽象掉大部分循环.
在不查看代码的情况下,我无法告诉您此选项是否是最佳前进方式,但您可以考虑这一点.
这是一个有趣的练习.我创建了一个名为ParallelList的对象,它接受可变数量的类型化列表,并且可以遍历每个索引处的值(作为值列表返回):
public class ParallelList<T> implements Iterable<List<T>> {
private final List<List<T>> lists;
public ParallelList(List<T>... lists) {
this.lists = new ArrayList<List<T>>(lists.length);
this.lists.addAll(Arrays.asList(lists));
}
public Iterator<List<T>> iterator() {
return new Iterator<List<T>>() {
private int loc = 0;
public boolean hasNext() {
boolean hasNext = false;
for (List<T> list : lists) {
hasNext |= (loc < list.size());
}
return hasNext;
}
public List<T> next() {
List<T> vals = new ArrayList<T>(lists.size());
for (int i=0; i<lists.size(); i++) {
vals.add(loc < lists.get(i).size() ? lists.get(i).get(loc) : null);
}
loc++;
return vals;
}
public void remove() {
for (List<T> list : lists) {
if (loc < list.size()) {
list.remove(loc);
}
}
}
};
}
}
Run Code Online (Sandbox Code Playgroud)
用法示例:
List<Integer> list1 = Arrays.asList(new Integer[] {1, 2, 3, 4, 5});
List<Integer> list2 = Arrays.asList(new Integer[] {6, 7, 8});
ParallelList<Integer> list = new ParallelList<Integer>(list1, list2);
for (List<Integer> ints : list) {
System.out.println(String.format("%s, %s", ints.get(0), ints.get(1)));
}
Run Code Online (Sandbox Code Playgroud)
哪个会打印出来:
1, 6
2, 7
3, 8
4, null
5, null
Run Code Online (Sandbox Code Playgroud)
此对象支持可变长度列表,但显然可以将其修改为更严格.
不幸的是我无法摆脱ParallelList构造函数上的一个编译器警告:A generic array of List<Integer> is created for varargs parameters,所以如果有人知道如何摆脱它,让我知道:)
您可以在for循环中使用第二个约束:
for (int i = 0; i < list1.length && i < list2.length; ++i)
{
doStuff(list1[i]);
doStuff(list2[i]);
}//for
Run Code Online (Sandbox Code Playgroud)
我遍历集合的首选方法之一是for-each循环,但正如oracle教程提到的那样,在处理并行集合时使用迭代器而不是for-each.
以下是Martinv.Löwis在一篇类似文章中的回答:
it1 = list1.iterator();
it2 = list2.iterator();
while(it1.hasNext() && it2.hasNext())
{
value1 = it1.next();
value2 = it2.next();
doStuff(value1);
doStuff(value2);
}//while
Run Code Online (Sandbox Code Playgroud)
迭代器的优点是它是通用的,所以如果你不知道正在使用什么集合,使用迭代器,否则如果你知道你的集合是什么,那么你就知道长度/大小函数,所以常规的for循环这里可以使用附加约束.(注意我在这篇文章中非常复数,因为一个有趣的可能性是集合使用的不同,例如一个可能是List,另一个可能是数组)
希望这有帮助.
| 归档时间: |
|
| 查看次数: |
30028 次 |
| 最近记录: |