2009-10-12 18 views
2

J'ai un calcul coûteux, dont le résultat que je voudrais mettre en cache. Y at-il un moyen de faire une carte avec deux clés? Je pense à quelque chose comme Map<(Thing1, Thing2), Integer>.Java: structure de données pour le résultat de calcul de mise en cache?

alors je pourrais vérifier:

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

pseudocode. Mais quelque chose dans ce sens.

Répondre

5

Vous devez créer une classe qui détient Thing1 et Thing2, par exemple:

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() { ... }; 
} 

ensuite l'utiliser:

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

Notez que vous devez implémenter equals et hashCode pour faire ce travail de code correctement. Si vous avez besoin que ce code soit thread-safe, jetez un oeil à ConcurrentHashMap.

+0

Eerie .. J'ai * juste * fait cela il y a cinq minutes, puis je suis tombé sur SO et j'ai vu ces questions ... Je recommanderais cette implémentation de la méthode hashCode (qui est juste l'implémentation eclipse par défaut): 'return (31 + thing1.hashCode()) * 31 + thing2.hashCode(); ' – Kip

+1

@Kip: En fait, je recommande d'utiliser' HashCodeBuilder', 'EqualsBuilder', et' CompareToBuilder' d'Apache Commons Lang. :-) –

+0

Il m'a fallu <10 minutes pour l'implémenter, et maintenant mon programme fonctionne dans 25% des cas. Sensationnel. –

2

Si vous utilisez Google Collections, sa classe MapMaker a une méthode makeComputingMap qui fait exactement ce que vous avez décrit. En bonus gratuit, il est également compatible avec les threads (implémente ConcurrentMap).

En ce qui concerne la chose deux touches, vous devrez faire une classe qui contient les deux clés et mettre en œuvre une mise en œuvre appropriée de equals, hashCode et (le cas échéant) compareTo qui fait la comparaison clé la façon dont vous voulez il.

+0

Je suis tout pour Google Collections, mais j'ai du mal à comprendre comment cela fonctionnerait. –

+0

Vous créez essentiellement un objet 'Function' qui appelle votre fonction' computeResult'.L'objet Google prendra soin d'appeler cette fonction et de mettre en cache sa valeur, lorsque vous obtenez l'élément approprié de la carte. :-) –

3

Semble comme vous voulez memoisation. La dernière tête de tronc de Functional Java a un type de produit de memoising P1 qui modélise un calcul dont le résultat est mis en cache.

Vous l'utiliser comme ceci:

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

Appel _1() la première fois se déroulera le calcul coûteux et le stocker dans le mémo. Après cela, le mémo est renvoyé à la place.

Pour vos "deux clés", vous souhaitez un type de paire simple. Java fonctionnel a aussi cela sous la forme de la classe P2<A, B>. Pour mémoriser une telle valeur, utilisez simplement P1<P2<A, B>>.

Vous pouvez également utiliser la classe Promise<A> au lieu de l'annotation. Cela a été dans la bibliothèque pendant un moment, donc vous auriez juste besoin du dernier binaire. Vous l'utiliser comme suit:

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

Pour obtenir le résultat, appelez simplement myThing.claim(). Promise<A> fournit également des méthodes pour mapper des fonctions sur le résultat même si le résultat n'est pas encore prêt. Vous devez import static fj.control.parallel.ParModule.parModule et fj.control.parallel.Strategy.sequentialStrategy. Si vous souhaitez que le calcul s'exécute dans son propre thread, remplacez sequentialStrategy par l'une des autres stratégies fournies par la classe Strategy.