2009-10-12 38 views
2

我有一個昂貴的計算,我想要緩存的結果。有兩種方法可以製作地圖嗎?我在想像Map<(Thing1, Thing2), Integer>Java:緩存計算結果的數據結構?

然後我可以檢查:

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

僞代碼。但是沿着這些線。

回答

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。

+0

Eerie ..我*只是*在五分鐘前做了這個,然後來到了所以看到這個問題......我推薦這個實現hashCode方法(這只是默認的eclipse實現):'return (31+ thing1.hashCode())* 31 + thing2.hashCode();' – Kip 2009-10-12 02:31:13

+1

@Kip:其實,我推薦使用Apache Commons Lang中的'HashCodeBuilder','EqualsBuilder'和'CompareToBuilder'。 :-) – 2009-10-12 02:34:53

+0

我花了不到10分鐘來實現這一點,現在我的程序在25%的時間內運行。哇。 – 2009-10-12 02:51:21

2

如果您使用Google Collections,其MapMaker類有一個makeComputingMap方法,完全按照您所描述的方法。作爲免費獎勵,它也是線程安全的(實施ConcurrentMap)。

至於兩鍵的事情,你將不得不作出一個包含這兩個鍵的一類,並實施適當的實施equalshashCode,以及(如適用)compareTo,做的鍵比較你所希望的方式它。

+0

我都是Google集合,但我很難理解這是如何工作的。 – 2009-10-12 02:42:17

+0

您基本上創建一個調用您的'computeResult'函數的'Function'對象。當您從地圖中獲取相應的項目時,Google對象將負責調用該函數並緩存其值。 :-) – 2009-10-12 02:57:14

3

聽起來像你想memoisation。 Functional Java的最新樹幹頭具有memmoising產品類型P1,該模型對結果進行高速緩存的計算進行建模。

你會使用這樣的:

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

調用_1()第一次將運行昂貴的計算,並將其存儲在備忘錄。之後,備忘錄將被返回。

對於你的「兩把鑰匙」,你想要一個簡單的配對類型。 Functional Java也有類P2<A, B>的形式。要記住這樣的值,只需使用P1<P2<A, B>>即可。

您也可以使用Promise<A>類代替memoisation。這已經在圖書館一段時間了,所以你只需要最新的二進制文件。您可以使用如下:

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類提供的其他策略之一。