假设我想反向遍历一个泛型迭代器,而不知道迭代器的内部结构,并且基本上没有通过无类型魔术作弊,并假设这可以是任何类型的迭代,它为迭代器提供服务;我们可以在运行时甚至通过宏来优化迭代器的反转吗?
转发
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]);
}
是否还有更多可用于消除阵列可能性的优化?
答案 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 迭代。
在为什么默认情况下,迭代器是片面的,我们可以注意到这一点:
E.g。 1:在标准输入上运行的迭代器。
E.g。 2:在抛物线或更复杂的球轨迹上运行的迭代器。
E.g。 3:略有不同,但考虑在非常大的单链表(例如,类
List
)上运行迭代器的性能问题。一些迭代器可以在迭代过程中被中断(Lambda.has()和Lambda.indexOf(),例如一旦匹配就返回,所以你通常不想想什么' s作为集合迭代,但更多作为可中断的系列或流程逐步迭代)。
虽然这并不意味着如果你需要它们,你不应该定义双向迭代器(我从来没有在Haxe中完成它,但它似乎不可能),在绝对具有双向迭代器并不是那么自然,并且强制执行迭代器会使编码变得复杂。
中间且更灵活的解决方案是在您需要的地方简单地使用ReverseXxIter
,例如ReverseIntIter
或Array.reverseIter()
(使用自定义ArrayExt类)。因此,每个程序员都要留下自己的答案,我认为这是一个很好的平衡点;虽然一开始需要更多时间和挫折(每个人都可能有同样的问题),但你最终会更好地了解语言,最终会给你带来好处。