2017-01-11 13 views
3

実際の再帰の例はそれほど多くありません。私は今日1つを見つけたと思うし、それを共有したいと思うQ &私はそれが魅力的だと思うので、スタイル。再帰によって条件を満たす多次元配列の最後の要素を見つける

私はゲームのためにPhaserエンジンを使用しています。ユーザーがクリックすると、ユーザーがクリックしたゲーム要素を見つける必要があります。これは、複数の要素が重ね合わされると複雑になります。次に、レンダリングの順序を確認し、最も高い要素を選択する必要があります。

Phaserでは、すべての表示オブジェクトのルートは「世界」です。既存の要素はすべて、世界の直接的な子どもであるか、または子供の子供である。それはゲームの世界が上にある分岐構造です。子は、レンダリング順に並べられます。つまり、最後のものが上に表示されます。

var world = [ 
    [ 
     18, 
     3, 
     [ 
      1, 
      14, 
      2 
     ], 
     5, 
     9, 
     [ 
      3, 
      5 
     ] 
    ], 
    [ 
     16, 
     7 
    ] 
]; 

二つの主な「グループ」とこの配列の三つのレベルがあります。ここ

番号で表される各表示オブジェクトを有する、この例です。ゲームの言葉では、2番目のグループは最初のグループの後に追加されるため、上に表示されます。最初のグループの中で、最後の要素がグループの上にレンダリングされます。そのグループの中で、最後の要素がもう一度上にレンダリングされます。これらの要素のうち、一番上にレンダリングされた要素は、最後の要素なので7です。

マウスをクリックすると、10より大きい数字(181416)で表されるすべての要素の上に表示されます。私が必要とするのは16なので、一番遠いです。

どうすれば入手できますか?

答えて

1

Array#forEachを再帰的アプローチで使用できます。

function getValue(array, cb) { 
 
    var last; 
 
    array.forEach(function iter(a) { 
 
     if (Array.isArray(a)) { 
 
      a.forEach(iter); 
 
      return; 
 
     } 
 
     if (cb(a)) { 
 
      last = a; 
 
     } 
 
    }); 
 
    return last; 
 
} 
 

 
function check(v) { 
 
    return v > 10; 
 
} 
 

 
var world = [[18, 3, [1, 14, 2], 5, 9, [3, 5]], [16, 7]]; 
 

 
console.log(getValue(world, check));

Array#reduce付きバージョンとコールバック上クロージャ。 4castleのanswer背中から反復とし、最初の発見と早期返却に触発

function getLastValue(cb) { 
 
    return function iter(r, a) { 
 
     return Array.isArray(a) ? a.reduce(iter, r) : cb(a) ? a : r; 
 
    }; 
 
} 
 

 
function greaterThan10(v) { 
 
    return v > 10; 
 
} 
 

 
var world = [[18, 3, [1, 14, 2], 5, 9, [3, 5]], [16, 7]]; 
 

 
console.log(world.reduce(getLastValue(greaterThan10), null));

補遺。

function getValue(array, cb) { 
 
    var i = array.length, r; 
 
    while (i--) { 
 
     if (Array.isArray(array[i])) { 
 
      r = getValue(array[i], cb); 
 
      if (r !== undefined) { 
 
       return r; 
 
      } 
 
     } 
 
     if (cb(array[i])) { 
 
      return array[i]; 
 
     } 
 
    }; 
 
} 
 

 
function check(v) { 
 
    return v > 10 && v < 16; 
 
} 
 

 
var world = [[18, 3, [1, 14, 2], 5, 9, [3, 5]], [16, 7]]; 
 

 
console.log(getValue(world, check)); // 14

+0

- 'Array.forEachを()'使用する利点は何ですか?私がそれを使用する場合は、現在のオブジェクトが配列であるかどうかをチェックして、それを数値で呼び出すのを避ける必要もあります。 forループを使用すると、数値をループさせようとすると、その長さは定義されず、ループは実行されません。 'length'があれば問題になるかもしれないが、実際は配列ではないと思う。 2番目のスニペットについて - それはどのように動作するのか少し説明できますか?私は以前に 'reduce()'を見たことがなく、何が起こるか把握するのに苦労しています。私はコードが好きです。 –

+1

関数を呼び出す前にサニティチェックを追加したり、適切な型が指定されていない場合は返されます。 'reduce'は配列を反復し、コールバックをとり、オプションとして開始値をとります。与えられたまたは最後の値と実際の値に新しい値の基数を戻します。この場合、コールバックは比較関数 'greaterThan10'をとり、returnのコールバックとして関数' iter'を返します。関数の内部では、配列をチェックし、reduce値またはchecked値のいずれかを返します。削減のもう一つの理由は、表現のようなクールな文章を書くことができます。 –

+0

なぜ 'forEach'であるのかということは、結果を保持するための外部変数を使ったちょうど従来のアプローチです。 –

0
function topElement(fn, object, data) { 
    if (fn(object) === true) { 
     data = object; 
    } 

    for (var i = 0; i < object.length; i++) { 
     data = topElement(fn, object[i], data); 
    } 

    return data; 
} 

function check(num) { 
    return (num > 10); 
} 

topElement(check, world); // 16 

異なる条件が必要だった場合は、check()メソッドを変更するだけです。私のゲームでは、別の条件は、ユーザーがクリックした場所です。 check()は、ゲーム要素をポイントと比較し、内部にある場合はtrueを返し、次にtopElement()は条件を満たすレンダリング順序を最も下回る要素を返します。

ここにはfiddleがあります。

1

いくつかの条件を満たしている多次元配列の最後の要素を取得するには、なるように、要素が配列であるかないことを確認するチェックのいくつかの種類を使用する必要がありますあなたは再帰的呼び出しをするかどうかを知っています。何かが配列であるかどうかを調べるには、Array.isArrayを使用するか、ダックタイピングを使用してlengthプロパティを調べることができます。

アレイ全体を後方にループすると、先頭のエレメントがより早く見つかるようになります。最初のスニペットについて

function topElement(condition, array) { 
 
    for (var i = array.length - 1; i >= 0; i--) { 
 
    var val = array[i]; 
 
    if (Array.isArray(val)) { 
 
     var top = topElement(condition, val); 
 
     if (top !== undefined) { 
 
     return top; 
 
     } 
 
    } else if (condition(val)) { 
 
     return val; 
 
    } 
 
    } 
 
    return undefined; 
 
} 
 

 
function check(num) { 
 
    return num > 10; 
 
} 
 

 
var world = [[18, 3, [1, 14, 2], 5, 9, [3, 5]], [16, 7]]; 
 
console.log(topElement(check, world));

関連する問題