【问题标题】:Iterable Sum in Java?Java中的可迭代总和?
【发布时间】:2011-06-13 02:25:47
【问题描述】:

有没有这样的库:

public class Iterables{
    private Iterables() {}

    public static <T> int sum(Iterable<T> iterable, Func<T, Integer> func) {
        int result = 0;
        for (T item : iterable)
            result += func.run(item);
        return result;
    }
}

public interface Func<TInput, TOutput> {
    TOutput run(TInput input);
}

【问题讨论】:

    标签: java


    【解决方案1】:

    基本上有两个有用的库可以帮助解决这个问题; Google GuavaApache Commons Collections

    您要做的基本上是两个操作,首先是映射,然后是归约。我自己从来没有在任何程度上使用过 Commons Collections,所以我不能告诉你更多关于它的信息,但我知道至少在 Google Guava 中不支持缩减(或折叠)(参见Issue 218)。不过,添加自己并不难(未经测试):

    interface Function2<A, B> {
      B apply(B b, A a);
    }
    
    public class Iterables2 {
        public static <A, B> B reduce(Iterable<A> iterable,
          B initial, Function2<A, B> fun) {
            B b = initial;
            for (A item : iterable)
                 b = fun.apply(b, item);
            return b;
        }
    }
    

    这样你就可以像这样将它与 Guavas Iterables.transform() 结合起来:

    class Summer implements Function2<Integer, Integer> {
        Integer apply(Integer b, Integer a) {
            return b + a;
        }
    }
    
    class MyMapper<T> implements Function<T, Integer> {
        Integer apply(T t) {
          // Do stuff
        }
    }
    

    然后(前提是你已经导入了相关的静态类):

    reduce(transform(iterable, new MyMapper()), 0, new Summer());
    

    另见this question

    【讨论】:

    • 你能修正你的例子吗?我在 fun.apply() 行得到The method apply(A) in the type Function&lt;A,B&gt; is not applicable for the arguments (B, A)
    • 也许吧。可能不是。答案是 5 岁,只需使用 Java 8 流 :)
    【解决方案2】:

    Java 不是函数式语言,通常只使用普通循环更简单、更快捷。

    你可以写类似的东西

    List<String> list = /* ... */
    int totalLength = Iterables.sum(list, new Func<String, Integer>() {
        public Integer run(String input) {
            return input.length();
        }
    });
    

    但是恕我直言,它更短更简单。

    List<String> list = /* ... */
    int totalLength = 0;
    for(String s: list) totalLength += s.length();
    

    当闭包成为 Java 的标准时,这将改变,但目前循环通常是最好的方法。

    【讨论】:

    • 请记住:shorter != easier to read,这是大多数程序员都没有意识到的认知偏差。
    • @Sridhar-Sarnobat 同意在使用 lambda,尤其是嵌套 lambda 时要注意这一点。例如a -&gt; b -&gt; a &gt; b 很短但不是很清楚。
    【解决方案3】:

    Functional Java 有 sum 方法:

    http://functionaljava.googlecode.com/svn/artifacts/3.0/javadoc/fj/function/Integers.html#sum%28fj.data.List%29

    这是一个例子:

    List<Integer> ints = new ArrayList<Integer>();
    ints.add(1);
    ints.add(2);
    ints.add(3);
    int sum = Integers.sum(fj.data.List.iterableList(ints));
    

    【讨论】:

      【解决方案4】:

      您可以简单地使用 Lamdaj - 一个以伪功能和静态类型的方式操作集合的库:

      sum = Lambda.sum(iterable);
      

      它还可以进行其他类型的聚合,或者您可以添加自己的聚合器:

      sum = Lambda.aggregate(seq, new InitializedPairAggregator<Integer>(0) {
          protected Integer aggregate(Integer first, Integer second) {
              return first + second;
          }
      });
      

      有关其他示例,请参阅 Features

      【讨论】:

        【解决方案5】:

        由于 Java 8 现已推出,因此获取集合的总和很简单:

        collection.stream().reduce(0, Integer::sum)
        

        不幸的是,流在迭代器上不可用,但总是可以转换。数组更简单:

        LongStream.of(1, 2, 3).sum()
        

        【讨论】:

        • 在 Java 8 中,如果“values”的类型为 Iterable,您可以使用 StreamSupport.stream(values.spliterator(), false) 来获取流
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2016-06-15
        • 1970-01-01
        • 2014-07-13
        • 1970-01-01
        • 2016-02-17
        • 2021-08-24
        • 2010-11-25
        相关资源
        最近更新 更多