2

私の状況に近い次の擬似コードスニペットを参照してください。

function foo () {
  for ( velocity=0; velocity<100; velocity++ ) {
    root1 = computeRoot1();
    root2 = computeRoot2();
    // do a bunch of computation with root1
    // if result of computation is undesirable, do computations again with root2 
  }

したがって、基本的には、forループの本体で。を使用して計算を実行しroot1、の計算結果が無効であるroot2場合に実行します。root1

私の最初の本能は、計算をヘルプ関数でラップするという明白なアプローチでしたが、これが最も明確なアプローチであるかどうかはわかりません。コード内の情報を適切にコロケーションしようとしていますが、コードを大幅に簡潔にすることなく、最大2回(反復ごとに)実行されるコードの関数呼び出しがその目標を達成できません。

私はおそらく次のforようなループを考えていました:

for ( root=root1; root1IsInvalid==true || bothRootsInvalid==true; root=root2 )

またはwhile同様の機能を備えた。しかし、私は確かに他の提案を受け入れています

このコードを読んでいる人として、どのアプローチが最も読みやすく簡潔になりますか?

余談ですが、私はこの特定の関数をJavaScriptで書いていますが、言語に依存しないソリューションは素晴らしいでしょう。

編集:明確化されたコードスニペット

4

2 に答える 2

3

いくつかの基本的なアプローチがあります。

  1. 値を配列に入れ、forループを使用して配列内の各項目で同じコードを実行し、条件が満たされたときに反復を停止する可能性があります。
  2. 計算を行う関数を作成してから、最初の関数を呼び出し、次に2番目の関数を呼び出すコードを記述します。
  3. ループを作成し、whileいくつかの条件が満たされるまでコードを繰り返します。

最初のオプションは、N個のアイテムに拡張する方が簡単です。2番目のオプションは、たった2つのアイテムの方がおそらく簡単です。

計算関数をローカル関数(現在実行している関数内で宣言および使用)にすることができるため、グローバル名前空間に追加されず、コードはよりカプセル化されたままになります。

また、この行で何をしようとしているのかもわかりません。

root1, root2 = computeRoots();

ただし、これは値を割り当てるだけであり、root2おそらくvarこれらの前でローカル変数として定義する必要があるようです。

于 2012-12-31T04:49:10.923 に答える
1

熱心な評価がOKの場合は、ルートを配列に収集し、それを使用roots.filter(isinvalid)して無効なルートを取り除くことができます。次に、結果の配列の最初の項目を使用します。

遅延評価が必要な場合は、これを関数に一般化して、null以外の結果が見つかるまで、配列に対して関数を遅延評価することができます。

// call fn on items in arr until fn returns non-null
// returns [item, result]
// if result===false, no true value was returned
function firstNotNull(fn, arr) {
    var i, length, item, result=null;
    for (i = 0, length=arr.length; i < length; i++) {
        item = arr[i];
        result = fn(item);
        if (result!==null) {
            break;
        }
    }
    return [item, result];
}


function rootComputations(root) {
    var computationResult = null;
    if (root==1) {
        computationResult = 1;
    }
    return computationResult;
}

function computeRoots() {
    return [0,1];
}

function foo() {
    var velocity, roots, root, result, computations;
    for (velocity = 0; velocity < 100; velocity++) {
        roots = computeRoots();
        computations = firstNotNull(rootComputations, roots);
        console.log(computations);
        root = computations[0];
        result = computations[1];
    }
}

foo();

firstNotNull()さらに一般化することができます:

// call fn on items in arr until cond(fn(item)) returns true
// returns [item, fn(item)], or null if unsatisfied
function firstSatisfying(cond, fn, arr) {
    var i, length, item, fnitem, result=null;
    for (i = 0, length=arr.length; i < length; i++) {
        item = arr[i];
        fnitem = fn(item);
        if (cond(fnitem)) {
            result = [item, fnitem];
            break;
        }
    }
    return result;
}

var firstNotNull = firstSatisfying.bind(null, function(item){return item!==null;});

これで、必要な条件を満たすもののリストの最初のものを取得するためのジェネリック関数ができました。

ECMAScript 5は、配列に対する熱心な機能アプリケーションをはるかに簡単にする多くのメソッドを追加しましたが、Javascriptには遅延評価のためのネイティブ機能がありません。これが頻繁に必要になると思われる場合は、部分適用のメソッドを備えた「ストリーム」データ型を提供するstream.jsの使用を検討してください。stream.jsを使用すると、ロジックは次のようになります。

// rootStream should be a function which returns a Stream
// It should construct a stream with the first root produced
// and a function that returns the remaining roots.
// Since I don't know how you get your roots, I'll use a stupid example:
function rootStream() {
    return new Stream(0, function(){
        return new Stream(1);
    });
}

function isvalid(root) {
    return root===1;
}

Stream.range(0,100)
.walk(function(v){
    //v doesn't seem to be used?
    var firstvalid = rootStream().filter(isvalid).head();
    console.log(firstvalid);
});
于 2012-12-31T05:44:40.067 に答える