迭代迭代迭代器的最快方法是什么?

时间:2012-11-26 16:38:45

标签: iterator haxe

假设我想反向遍历一个泛型迭代器,而不知道迭代器的内部结构,并且基本上没有通过无类型魔术作弊,并假设这可以是任何类型的迭代,它为迭代器提供服务;我们可以在运行时甚至通过宏来优化迭代器的反转吗?

转发

var a = [1, 2, 3, 4].iterator();
// Actual iteration bellow
for(i in a) {
   trace(i);
}

向后

var a = [1, 2, 3, 4].iterator();
// Actual reverse iteration bellow
var s = [];
for(i in a) {
    s.push(i);    
}
s.reverse();
for(i in s) {
    trace(i);    
}

我认为必须有一种更简单的方法,或者至少是快速的方法。我们无法知道一个大小,因为Iterator类没有携带一个,所以我们不能将推送反转到临时数组。但我们可以删除反向,因为我们知道临时数组的大小。

var a = [1,2,3,4].iterator();
// Actual reverse iteration bellow
var s = [];
for(i in a) {
    s.push(i);    
}
var total = s.length;
var totalMinusOne = total - 1;
for(i in 0...total) {
    trace(s[totalMinusOne - i]);    
}

是否还有更多可用于消除阵列可能性的优化?

2 个答案:

答案 0 :(得分:5)

我不得不重复这个列表,但是......这很讨厌。我的意思是,如果数据结构是正确的数据格式,那么数据结构肯定是一个数组。将数据复制到数组(“[]”)的更好的事情(更少的内存碎片和重新分配)可能是链接的列表或哈希。

但是如果我们使用数组,那么我们应该使用数组理解(http://haxe.org/manual/comprehension),至少在Haxe 3或更高版本中使用:

var s = array(for (i in a) i);

理想情况下,至少对于多次访问的大型迭代器,应缓存s。

要读回数据,你可以做一些不那么罗嗦的事情,但是非常讨厌,比如:

for (i in 1-s.length ... 1) {
    trace(s[-i]);
}

但那不是很可读,如果你的速度很快,那么创建一个全新的迭代器只是为了循环数组,无论如何都是笨重的。相反,我更喜欢稍长但更清洁,可能更快,可能更少的内存:

var i = s.length;
while (--i >= 0) {
    trace(s[i]);
}

答案 1 :(得分:3)

首先,我同意Dewi Morgan重复迭代器产生的输出来反转它,有点违背其目的(或至少它的一些好处)。有时候它还可以。

现在,关于技术答案:

根据定义,Haxe中的基本迭代器只能计算 next 迭代。

为什么默认情况下,迭代器是片面的,我们可以注意到这一点:

  1. 如果所有迭代器都可以向后和向前运行,则Iterator类将花费更多时间来编写。
  2. 并非所有迭代器都在集合或一系列数字上运行。
  3.   

    E.g。 1:在标准输入上运行的迭代器。

         

    E.g。 2:在抛物线或更复杂的球轨迹上运行的迭代器。

         

    E.g。 3:略有不同,但考虑在非常大的单链表(例如,类List)上运行迭代器的性能问题。一些迭代器可以在迭代过程中被中断(Lambda.has()和Lambda.indexOf(),例如一旦匹配就返回,所以你通常不想想什么' s作为集合迭代,但更多作为可中断的系列或流程逐步迭代)。

    虽然这并不意味着如果你需要它们,你不应该定义双向迭代器(我从来没有在Haxe中完成它,但它似乎不可能),在绝对具有双向迭代器并不是那么自然,并且强制执行迭代器会使编码变得复杂。

    中间且更灵活的解决方案是在您需要的地方简单地使用ReverseXxIter,例如ReverseIntIterArray.reverseIter()(使用自定义ArrayExt类)。因此,每个程序员都要留下自己的答案,我认为这是一个很好的平衡点;虽然一开始需要更多时间和挫折(每个人都可能有同样的问题),但你最终会更好地了解语言,最终会给你带来好处。