Java 中的记忆化

发布于 2024-12-17 05:57:29 字数 1183 浏览 0 评论 0原文

好吧,在 C# 中我可以这样写:

public class Memorizer<K,TRes>
{
    private Dictionary<K,TRes> _mem;
    private Func<K,TRes> _function

    public Memorizer (Func<K,TRes> function)
    {
        _function = function;
        _mem= new Dictionary<K,TRes>();
    }

    public TRes Call(K arg)
    {
        if (mem.ContainsKey(arg)
        {
            return _mem[arg];
        }
        else
        {
            TRes ret=_function(arg);
            _mem[arg] = ret;
            return ret;
        }
    }
}

这可以用来获得明显的收益:

public class FactorialCalculator()
{
    private Memorizer<ushort, ulong> _memorizedFactorial;
    public FactorialCalculator()
    {
        _memorizedFactorial = new Memorizer<ushort, ulong> (innerFactorial);
    }

    private ulong innerFactorial(ushort x)
    {
        return (x=0) ? 1 : x*Factorial(x-1)
    }

    public ulong factorial(ushort x)
    {
        _memorizedFactorial.Call(x);
    }

}

我确信它可以变得更加通用和优雅。 我知道如果 x>20 就会出现溢出异常。 (而且我也可能有类型转换错误) 但希望我表达了我的观点:我可以创建一个类,可以满足纯数学函数(即确定性、无副作用函数)记忆的需求 并获得惊人的性能提升。

我怎样才能在Java中完成类似的事情?

Ok so in C# I could write:

public class Memorizer<K,TRes>
{
    private Dictionary<K,TRes> _mem;
    private Func<K,TRes> _function

    public Memorizer (Func<K,TRes> function)
    {
        _function = function;
        _mem= new Dictionary<K,TRes>();
    }

    public TRes Call(K arg)
    {
        if (mem.ContainsKey(arg)
        {
            return _mem[arg];
        }
        else
        {
            TRes ret=_function(arg);
            _mem[arg] = ret;
            return ret;
        }
    }
}

Which could be made use of for obvious gains:

public class FactorialCalculator()
{
    private Memorizer<ushort, ulong> _memorizedFactorial;
    public FactorialCalculator()
    {
        _memorizedFactorial = new Memorizer<ushort, ulong> (innerFactorial);
    }

    private ulong innerFactorial(ushort x)
    {
        return (x=0) ? 1 : x*Factorial(x-1)
    }

    public ulong factorial(ushort x)
    {
        _memorizedFactorial.Call(x);
    }

}

I'm sure it could be made more general and elegant.
And I know I'll have overflow exceptions if x>20.
(And I may have typecast errors in there too)
BUt hopefully I made my point: i can create a class that can furful the needs for memoisation of pure mathematical functions (I.e. deterministic, side-effect free functions)
and get wonderful performance gains.

How can I accomplish a similar thing in Java?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

想你只要分分秒秒 2024-12-24 05:57:29

在Java 8中,您可以使用computeIfAbsent来实现记忆化:

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;

public class FactorialCalculator {

public static void main(String[] args) {

    Function<Integer, Long> factorialFunction = x -> {
        System.out.println("Calculating factorial for " + x);
        long fact = 1;
        for (int i = 1; i <= x; i++) {
            fact *= i;
        }
        return fact;
    };

    Function<Integer, Long> memoziedFactorialFunction = memoise(factorialFunction);

    System.out.println(memoziedFactorialFunction.apply(5));
    System.out.println(memoziedFactorialFunction.apply(5));
    System.out.println(memoziedFactorialFunction.apply(5));
    System.out.println(memoziedFactorialFunction.apply(5));
    System.out.println(memoziedFactorialFunction.apply(6));
    System.out.println(memoziedFactorialFunction.apply(6));

}

public static <X, Y> Function<X, Y> memoise(Function<X, Y> fn) {
    Map<X, Y> pp = new ConcurrentHashMap<X, Y>();
    return (a) -> pp.computeIfAbsent(a, fn);
}

}

结果是:

Calculating factorial for 5
120
120
120
120
Calculating factorial for 6
720
720

更多详细信息请参见http://rdafbn.blogspot.ie/2015/06/memoize-functions-in-java-8.html

最后,您可以使用 cyclops 库删除创建 memoize 泛型方法的样板代码(看看http://static.javadoc.io/com.aol.cyclops/cyclops-functions/4.0.2/com/aol/cyclops/functions/Memoise.html)

In Java 8 you can use the computeIfAbsent to achieve memoization :

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;

public class FactorialCalculator {

public static void main(String[] args) {

    Function<Integer, Long> factorialFunction = x -> {
        System.out.println("Calculating factorial for " + x);
        long fact = 1;
        for (int i = 1; i <= x; i++) {
            fact *= i;
        }
        return fact;
    };

    Function<Integer, Long> memoziedFactorialFunction = memoise(factorialFunction);

    System.out.println(memoziedFactorialFunction.apply(5));
    System.out.println(memoziedFactorialFunction.apply(5));
    System.out.println(memoziedFactorialFunction.apply(5));
    System.out.println(memoziedFactorialFunction.apply(5));
    System.out.println(memoziedFactorialFunction.apply(6));
    System.out.println(memoziedFactorialFunction.apply(6));

}

public static <X, Y> Function<X, Y> memoise(Function<X, Y> fn) {
    Map<X, Y> pp = new ConcurrentHashMap<X, Y>();
    return (a) -> pp.computeIfAbsent(a, fn);
}

}

Result is :

Calculating factorial for 5
120
120
120
120
Calculating factorial for 6
720
720

More details here http://rdafbn.blogspot.ie/2015/06/memoize-functions-in-java-8.html

Lastly, you can use the cyclops library to remove the boilerplate code of creating memoize generic methods( have a look at http://static.javadoc.io/com.aol.cyclops/cyclops-functions/4.0.2/com/aol/cyclops/functions/Memoise.html)

丢了幸福的猪 2024-12-24 05:57:29

java 中不能将函数作为数据类型传递。要解决此问题,请使用接口。

public interface ReturnFunction<K, V> {
    public V getValue(K k);
}

现在您可以将innerFactorial 设置为数据类型。

public ReturnFunction<Short, Long> innerFactorial = new ReturnFunction<Short, Long>(){
    public Long getValue(Short x){
        return (x=0) ? 1 : x*Factorial(x-1);
    }
};

这允许您将 innerFactorial 作为数据类型传递:

_memoizedFactorial = new Memorizer<Short, Long> (innerFactorial);

并调用您编写的函数:

long someLong = _memoizedFactorial.getValue(someShort);

另外,在 Java 中不要将字段或方法名称大写。它不是标准的,并且使代码更难阅读。

You can't pass functions as data types in java. To fix this, use an interface.

public interface ReturnFunction<K, V> {
    public V getValue(K k);
}

Now you can set innerFactorial to a data type.

public ReturnFunction<Short, Long> innerFactorial = new ReturnFunction<Short, Long>(){
    public Long getValue(Short x){
        return (x=0) ? 1 : x*Factorial(x-1);
    }
};

This lets you pass innerFactorial as a data type:

_memoizedFactorial = new Memorizer<Short, Long> (innerFactorial);

And to call the function you write this:

long someLong = _memoizedFactorial.getValue(someShort);

Also, in Java don't capitalize field or method names. It's not standard and makes the code harder to read.

深海夜未眠 2024-12-24 05:57:29

查看 Guava 的 缓存包。这就是它的用途。

Check out Guava's cache package. This is what it is for.

飘过的浮云 2024-12-24 05:57:29

您无法在 Java 中从 创建泛型映射,因为泛型类型参数仅绑定到引用类型。您必须将其设为,这涉及包装原语,并且可能会给您的记忆带来一些开销。

除此之外,Java 的翻译非常简单。请注意,您只能记住提供有用的 equals 和 hashCode 实现的类型,并且需要使用大小有限制的、线程安全的弱键表例如 MapMaker

You can't create a generic map from <short, ulong> in Java because generic type parameters only bind to reference types. You would have to make it <Short, Long> which involves wrapping primitives and may introduce some overhead into your memoization.

Besides that, the translation to Java is pretty straight-forward. Just be aware, you can only memoize types that provide a useful equals and hashCode implementations, and you need to use a size-bounded, thread-safe, weak-key table such as that provided by MapMaker.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文