7

イテレータの内部について知らずに、本質的に型指定されていない魔法を介してごまかすことなく、イテレータを提供する任意のタイプのイテラブルである可能性があると想定せずに、一般的なイテレータを逆に繰り返し処理したいとしましょう。実行時にイテレータの逆を最適化したり、マクロを介して最適化したりすることはできますか?

フォワード

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]);    
}

配列の可能性を取り除くために使用できる最適化は他にありますか?

4

3 に答える 3

5

ただし、リストを複製する必要があるのは気になります...それは厄介です。つまり、それが適切なデータ形式である場合、データ構造はすでに配列であるということです。それをコピーする配列(「[]」)よりも優れたもの(メモリの断片化と再割り当てが少ない)は、リンクされたリストまたはハッシュである可能性があります。

しかし、配列を使用している場合、少なくともHaxe 3以降では配列内包表記( http://haxe.org/manual/comprehension )を使用する必要があります:

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]);
}
于 2014-03-06T01:17:33.093 に答える
3

まず第一に、Dewi Morgan が反復子によって生成された出力を複製してそれを逆にすることに同意し、その目的(または少なくともその利点の一部) をやや無効にします。たまになら大丈夫ですけどね。

さて、技術的な答えについて:

定義により、Haxe の基本イテレータは次のイテレーションしか計算できません。

イテレータがデフォルトで片面である理由については、次のことがわかります。

  1. イテレータが前後に実行できる場合は、Iterator クラスの作成に時間がかかります。
  2. すべての反復子がコレクションまたは一連の数値に対して実行されるわけではありません。

例 1: 標準入力で実行される反復子。

例 2: ボールの放物線またはより複雑な軌道上で実行される反復子。

例 3: わずかに異なりますが、非常に大きな単一リンク リスト (例: class ) でイテレータを実行する際のパフォーマンスの問題について考えてみてListください。一部の反復子は、反復の途中で中断される可能性があります (たとえば Lambda.has() および Lambda.indexOf() は、一致するとすぐに返されるため、通常、反復されるものをコレクションとして考えたくありませんが、中断可能なシリーズまたは段階的に繰り返されるプロセスとして)。

これは、必要に応じて双方向イテレータを定義してはならないという意味ではありませんが (Haxe で実行したことはありませんが、不可能ではないようです)、絶対的に双方向イテレータを持つことはそれほど自然ではありません。 、そして反復子をそのように強制すると、コーディングが複雑になります。

中間的でより柔軟な解決策は、ReverseXxIter必要な場所、たとえばReverseIntIter、またはArray.reverseIter()(カスタム ArrayExt クラスを使用して) を単純に持つことです。したがって、すべてのプログラマーが独自の回答を作成する必要があります。バランスが取れていると思います。最初はもっと時間とフラストレーションがかかりますが (おそらく誰もが同じ種類の質問をしたでしょう)、言語をよりよく知るようになり、最終的にはメリットがあります。

于 2014-09-06T17:48:47.817 に答える
0

Dewi Morganの投稿を補完してfor(let i = a.length; --i >= 0;) i;、メソッドを簡素化したい場合に使用できますwhile() 。本当にインデックス値が必要な場合はfor(let i=a.length, k=keys(a); --i in k;) a[k[i]]; 、パフォーマンスを維持するために与えるのが最善だと思います。よりきれいな書き方のものもfor(let i of keys(a).reverse()) a[i];ありますが、その反復率は を使用して 1n 増加します.reduce()

于 2021-12-31T14:51:35.340 に答える