2

我有一个昂贵的计算,我想缓存它的结果。有没有办法用两个键制作地图?我在想类似的东西Map<(Thing1, Thing2), Integer>

然后我可以检查:

if (! cache.contains(thing1, thing2)) {
  return computeResult();
}
else {
  return cache.getValue(thing1, thing2);
}

伪代码。但是有些类似的东西。

4

3 回答 3

5

您需要创建一个包含 Thing1 和 Thing2 的类,例如:

class Things {
    public final Thing1 thing1;
    public final Thing2 thing2;
    public Things(Thing1 thing1, Thing2 thing2) {
      this.thing1 = thing1; 
      this.thing2 = thing2;
    }
    @Override
    public boolean equals(Object obj) { ... }
    @Override
    public int hashCode() { ... };
 }

然后使用它:

Things key = new Things(thing1, thing2);
if (!cache.contains(key) {
    Integer result = computeResult();
    cache.put(key, result);
    return result;
} else {
    return cache.getValue(key);
}

请注意,您必须实现 equals 和 hashcode 才能使此代码正常工作。如果您需要此代码是线程安全的,请查看 ConcurrentHashMap。

于 2009-10-12T02:28:15.503 回答
3

听起来你想要记忆。最新的函数式 Java主干头有一个记忆产品类型P1,它对计算结果进行建模,其结果被缓存。

你会像这样使用它:

P1<Thing> myThing = new P1<Thing>() {
  public Thing _1() {
    return expensiveComputation();
  }
}.memo();

第一次调用 _1() 将运行昂贵的计算并将其存储在备忘录中。之后,将返回备忘录。

对于您的“两个键”,您需要一个简单的对类型。函数式 Java 也有这个类的形式P2<A, B>。要记住这样的值,只需使用P1<P2<A, B>>.

你也可以使用Promise<A>类而不是记忆。这在库中已经有一段时间了,所以你只需要最新的二进制文件。您可以按如下方式使用它:

Promise<Thing> myThing =
  parModule(sequentialStrategy).promise(new P1<Thing>() {
    public Thing _1() {
      return expensiveComputation();
    }
  });

要得到结果,只需调用myThing.claim(). Promise<A>还提供了在结果上映射函数的方法,即使结果还没有准备好

你需要import static fj.control.parallel.ParModule.parModulefj.control.parallel.Strategy.sequentialStrategy。如果您希望计算在其自己的线程中运行,请替换为该类sequentialStrategy提供的其他策略之一。Strategy

于 2009-10-12T02:38:51.800 回答
2

如果您使用Google Collections,它的MapMaker类有一个makeComputingMap完全按照您描述的方法。作为免费奖励,它也是线程安全的(实现ConcurrentMap)。

至于两个键的东西,您将必须创建一个包含两个键的类,并实现一个合适的equalshashCode和 (如果适用)compareTo实现,以您想要的方式进行键比较。

于 2009-10-12T02:25:12.907 回答