4

メソッドの開始時に、メソッドが以前にこれらの正確なパラメーターで呼び出されたかどうかを確認し、そうであれば、その時点で返された結果を返します。

最初は 1 つのパラメーターで Dictionary を使用していましたが、現在は 3 つのパラメーター (文字列、オブジェクト、ブール値) をチェックする必要があります。

私は次のようにカスタムオブジェクトを作成しようとしました:

var cacheKey:Object = { identifier:identifier, type:type, someBoolean:someBoolean };

//if key already exists, return it (not working)
if (resultCache[cacheKey]) return resultCache[cacheKey];

//else: create result ...

//and save it in the cache
resultCache[cacheKey] = result;

しかし、関数が 2 回目に呼び出されると、プロパティが同じであっても、新しい cacheKey は最初のオブジェクトと同じではないため、これは機能しません。

だから私の質問は:一致するキーのキーとして使用されるオブジェクトのプロパティをチェックするデータ型はありますか?

そして、私の最良の選択肢は他に何ですか?キーのキャッシュも作成しますか? :/

4

1 に答える 1

3

技術的な解決策には、等価比較インデックス作成という 2 つの側面があることに注意してください。

クリフ ノーツ バージョン:

  • カスタム等価比較を行うのは簡単です
  • インデックス作成を実行するには、あるオブジェクトが別のオブジェクトと等しいかどうかだけでなく、どちらのオブジェクトが他のオブジェクトよりも「大きい」かを知る必要があります。
  • すべてのプロパティがプリミティブである場合は、それらを単一の文字列に押しつぶしObject、それらを追跡するために an を使用する必要があります ( a ではありませんDictionary)。
  • 参照の等価性について個々のプロパティのいくつかを比較する必要がある場合は、どのプロパティ セットが他のプロパティ セットよりも大きいかを判断する関数を作成し、比較関数の出力を使用する独自のコレクション クラスを作成します。独自の二分探索木ベースのインデックス作成を実装します。
  • 引数の一意のセットの数が数百以下で、Object引数の参照比較が必要な場合は、配列とsomeメソッドを使用して、キャッシュされたすべてのキーに対して単純な比較を行います。実際のメソッドがどれほど高価であるかを知っているのはあなただけなので、ルックアップ コスト (関数に提供される一意の引数の数によって異なります) を許容できるかどうかは、あなた次第です。

等価比較

等価比較に対処するには、参照の等価性ではなく、オブジェクトのプロパティの値を比較するコードを簡単に記述できます。次の関数は厳密なセット比較を強制するため、両方のオブジェクトに同じ値を持つまったく同じプロパティ (どちらのオブジェクトにもプロパティを追加することはできません) が含まれている必要があります。

public static propsEqual(obj1:Object, obj2:Object):Boolean {
    for(key1:* in obj1) {
        if(obj2[key1] === undefined)
            return false;
        if(obj2[key1] != obj2[key1])
            return false;
    }
    for(key2:* in obj2) 
        if(obj1[key2] === undefined)
            return false;
    return true;
}

{A:1, B:2}に等しいと見なされるトレードオフで 2 番目の for ループを削除することで、速度を上げることができます{A:1, B:2, C:'An extra property'}

索引付け

あなたの場合、これに関する問題は、参照の等価性を提供する、または文字列キーを提供するインデックス付けを失うことです。を使用するなど、新しい関数引数の各セットを以前に見た引数のリスト全体と比較する必要があります。フィールドとメソッドを使用して、毎回新しいクロージャを生成しないようにしています。DictionaryObjectArray.somecurrentArgs

private var cachedArgs:Array = [];
private var currentArgs:Object;

function yourMethod(stringArg:String, objArg:Object, boolArg:Boolean):* {
    currentArgs = { stringArg:stringArg, objArg:objArg, boolArg:boolArg };
    var iveSeenThisBefore:Boolean = cachedArgs.some(compareToCurrent);
    if(!iveSeenThisBefore)
        cachedArgs.push(currentArgs);
}

function compareToCurrent(obj:Object):Boolean {
    return someUtil.propsEqual(obj, currentArgs);
}

これは、比較が O(n) 回になることを意味します。ここで、n は関数引数の一意のセットの増加し続ける数です。

関数のすべての引数がプリミティブである場合は、よく似た質問In AS3, where do you draw the line between Dictionary and ArrayCollection? を参照してください。. タイトルはあまり似ていないように聞こえますが、受け入れられた回答の解決策(はい、私が書きました)は、まったく同じ技術的な問題に対処しています-複数のプリミティブ値を単一の複合キーとして使用しています。あなたの場合の基本的な要点は次のとおりです。

private var cachedArgs:Object = {};

function yourMethod(stringArg:String, objArg:Object, boolArg:Boolean):* {
    var argKey:String = stringArg + objArg.toString() + (boolArg ? 'T' : 'F');
    if(cachedArgs[argKey] === undefined)
        cachedArgs[argKey] = _yourMethod(stringArg, objArg, boolArg);
    return cachedArgs[argKey];
}

private function _yourMethod(stringArg:String, objArg:Object, boolArg:Boolean):* {
    // Do stuff 
    return something;
}

どの参照が別の参照よりも「大きい」かを本当に判断する必要がある場合 (Dictionaryが内部的に行うように)、Adobe は「値」/「アドレス」を取得するための API をまだ提供していないため、いくつかの醜いものに足を踏み入れる必要があります。 "参照の。私がこれまでに見つけた最高のものは、この興味深いハックです: How can I get an instance's "memory location" in ActionScript? . 一連のパフォーマンス テストを行わないと、このハックを使用して参照を比較すると、バイナリ サーチ ツリーの indexnig によって得られる利点が失われるかどうかわかりません。当然、キーの数によって異なります。

于 2013-01-04T16:15:05.687 に答える