4

在方法的开头,我想检查之前是否使用这些确切的参数调用了该方法,如果是,则返回当时返回的结果。

起初,我使用一个参数,使用字典,但现在我需要检查 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;

但这不起作用,因为第二次调用该函数,新的 cacheKey与第一次不是同一个对象,即使它的属性相同。

所以我的问题是:是否有一种数据类型可以检查用作匹配键的对象的属性?

还有什么是我最好的选择?也为键创建缓存?:/

4

1 回答 1

3

请注意,技术解决方案有两个方面:相等比较索引

悬崖笔记版本:

  • 自定义相等比较很容易
  • 为了执行索引,您需要知道的不仅仅是一个对象是否等于另一个对象——您需要知道哪个对象比另一个对象“更大”。
  • 如果您的所有属性都是原语,您应该将它们压缩成一个字符串并使用 anObject来跟踪它们(不是 a Dictionary)。
  • 如果您需要比较某些单个属性的引用相等性,您将编写一个函数来确定哪一组属性大于另一组,然后创建自己的使用比较函数输出的集合类实现自己的基于二叉搜索树的索引。
  • 如果唯一参数集的数量在数百个或更少,并且您确实需要对Object参数进行引用比较,则只需使用 Array 和该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;
}

您可以通过消除第二个 for 循环来加速它,权衡{A:1, B:2}将被视为等于{A:1, B:2, C:'An extra property'}.

索引

在您的情况下,问题在于您丢失了a提供的引用相等或 a提供的字符串键的索引。您必须将每组新的函数参数与先前看到的参数的整个列表进行比较,例如使用. 我使用字段和方法来避免每次都生成新的闭包。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 是不断增加的唯一函数参数集的数量。

如果您的函数的所有参数都是原始的,请参阅非常相似的问题在 AS3 中,您在哪里画出 Dictionary 和 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内部那样),您将不得不涉足一些丑陋的东西,因为 Adob​​e 尚未提供任何 API 来检索“值”/“地址” "的参考。到目前为止,我发现的最好的事情是这个有趣的 hack:如何在 ActionScript 中获取实例的“内存位置”?. 如果不做一堆性能测试,我不知道使用这个 hack 来比较引用是否会扼杀二叉搜索树 indexnig 获得的优势。当然,这取决于密钥的数量。

于 2013-01-04T16:15:05.687 回答