I have an expensive computation, the result of which I'd like to cache. Is there some way to make a map with two keys? I'm thinking of something like Map<(Thing1, Thing2), Integer>.
Then I could check:
if (! cache.contains(thing1, thing2)) {
return computeResult();
}
else {
return cache.getValue(thing1, thing2);
}
pseudocode. But something along those lines.
You need to create a class that holds Thing1 and Thing2, e.g:
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() { ... };
}
Then to use it:
Things key = new Things(thing1, thing2);
if (!cache.contains(key) {
Integer result = computeResult();
cache.put(key, result);
return result;
} else {
return cache.getValue(key);
}
Note you have to implement equals and hashcode to make this code work properly. If you need this code to be thread-safe then have a look at ConcurrentHashMap.
Sounds like you want memoisation. The latest trunk head of Functional Java has a memoising product type P1 that models a computation whose result is cached.
You would use it like this:
P1<Thing> myThing = new P1<Thing>() {
public Thing _1() {
return expensiveComputation();
}
}.memo();
Calling _1() the first time will run the expensive computation and store it in the memo. After that, the memo is returned instead.
For your "two keys", you'd want a simple pair type. Functional Java has this too in the form of the class P2<A, B>. To memoise such a value, simply use P1<P2<A, B>>.
You can also use the Promise<A> class instead of the memoisation. This has been in the library for a while, so you'd just need the latest binary. You would use that as follows:
Promise<Thing> myThing =
parModule(sequentialStrategy).promise(new P1<Thing>() {
public Thing _1() {
return expensiveComputation();
}
});
To get the result out, simply call myThing.claim(). Promise<A> also provides methods for mapping functions over the result even if the result is not yet ready.
You need to import static fj.control.parallel.ParModule.parModule and fj.control.parallel.Strategy.sequentialStrategy. If you want the computation to run in its own thread, replace sequentialStrategy with one of the other strategies provided by the Strategy class.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With