一个很简单的问题,不过今天被问到了,一下子也说不出应该调用哪个方法,想想挺好玩:有一个linkedlist,现在要对它做遍历,对遍历到的每一个元素A,需要对从A到尾节点的所有元素再进行一次遍历,完成一个嵌套循环
最直接的方式就是:
int index = 0;
for (Iterator<Integer> i = list.iterator(); i.hasNext();) {
Integer num = i.next();
index++;
boolean startLoopWork = false;
int innerIndex = 0;
for(Iterator<Integer> j = list.iterator(); i.hasNext();) {
Integer num2 = j.next();
innerIndex++;
startLoopWork = startLoopWork || index == innerIndex-1;
if (startLoopWork) {
// do something
System.out.println(num + ":" + num2);
}
}
}
虽然直接,但是意图表达的不是很直接,那么在内层就直接对sublist进行遍历吧:
int anotherIndex = 0;
for (Iterator<Integer> i = list.iterator(); i.hasNext();anotherIndex++) {
Integer num = i.next();
if (anotherIndex >= list.size()) break;
List<Integer> subList = list.subList(anotherIndex+1, list.size());
for(Iterator<Integer> j = subList.iterator(); j.hasNext();) {
Integer num2 = j.next();
// do something
System.out.println(num + ":" + num2);
}
}
这个实际上也就是list.listIterator(index)做的事情,恩,list已经有这样的一个接口了:
for (ListIterator<Integer> i = list.listIterator(); i.hasNext();) {
Integer num = i.next();
for (Iterator<Integer> innerIterator = list.listIterator(i.nextIndex()); innerIterator.hasNext();) {
Integer innerNum = innerIterator.next();
// do something
System.out.println(num + ":" + innerNum);
}
}
这样的实现下,innerIterator是一个O(n)算法,不过由于链表中的元素是private的Entry对象,对外不可见,所以...我觉得这个限制使得扩展性不够好,不知道有什么特别考虑么?望知道的朋友告知
最后看一个scala的实现,scala中对链表统一抽象成head::rest:
@tailrec
def doubleIterate[A](list: List[A])(f: (A, Option[A]) => Unit): Unit = { list match { case (head :: Nil) => f(head, None) case (head :: rest) => rest.foreach (each => f(head, Some(each))) doubleIterate(rest)(f) } }
借助了scala的模式匹配机制,虽然写起来一样的繁琐,但是意图表达的比较清楚
这个实现的问题是只能应用于链表,而无法应用到其他的可以迭代的结构,比如array,string等,不过scala中并没有提供像java这样直接的api,所以为了能对所有具有iterable特性的数据结构进行这样的操作,还是只能回到原始的做法:
def doubleIterateIterable[A](iterable: Iterable[A])(f: (A, A) => Unit) = { var index = 0 iterable.foreach { i => index = index + 1 iterable.iterator.drop(index).foreach(j => f(i, j)) } }
这里,间接性主要来自于闭包,不过scala的iterable特性没有提供foreachWithIndex这样的方法。话说java中应该也有类似drop的接口吧。