代码之家  ›  专栏  ›  技术社区  ›  Nick ODell

传递非关联函数以减少

  •  8
  • Nick ODell  · 技术社区  · 8 年前

    我的程序有这样一行:

    Function<String, Integer> f = (String s) -> s.chars().reduce(0, (a, b) -> 2 * a + b);
    

    传递给reduce的函数不关联。Reduce的文档说,传递的函数必须是关联的。

    我怎样才能把它改写成一个不破坏reduce契约的表达式呢?

    2 回复  |  直到 8 年前
        1
  •  6
  •   Eugene    8 年前

    在当前情况下 如果你不打算使用并行 -你现在拥有的东西是安全的。显然,如果你同意这些免责声明。

    或者,您可以使用for循环创建函数:

     Function<String, Integer> f = s -> {
            int first = s.charAt(0) * 2 + s.charAt(1);
            int total = first;
    
            for (int x = 1; x < s.length() - 1; x++) {
                total = total * 2 + s.charAt(x + 1);
            }
    
            return total;
    
        };
    
        2
  •  3
  •   Holger    8 年前

    可以将此函数转换为关联函数,如中所述 this answer List.hashCode() . 差异仅在于因素( 2 vs。 31 )和起始值( 1 vs。 0 ).

    它可以适应您的任务,当您有随机访问输入(如 String :

    Function<String, Integer> f =
        s -> IntStream.range(0, s.length()).map(i -> s.charAt(i)<<(s.length()-i-1)).sum();
    

    这甚至可以并行运行,但您不太可能遇到如此庞大的字符串,以至于并行计算会带来好处。所以剩下的是,大多数人可能认为这个解决方案不如简单的 for


    请注意,上述解决方案表现出不同的溢出行为,即如果 一串 char s、 由于使用了移位运算符,而不是与2相乘。
    此问题的修复使解决方案更加高效:

    Function<String, Integer> f = s ->
        IntStream.range(Math.max(0, s.length()-32), s.length())
                 .map(i -> s.charAt(i)<<(s.length()-i-1)).sum();
    

    如果字符串大于32 烧焦 s、 它只处理最后32个 烧焦 s、 这已经足以计算与原始函数相同的结果。