开发者

Iterable Sum in Java?

Is there a library that does this:

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;
开发者_如何学Python    }
}

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


There are basically two useful libraries that can help with this; Google Guava and Apache Commons Collections.

What you are trying to do is basically two operations, first mapping, then reduction. I've never used Commons Collections to any extent myself so I can't tell you more about that, but I know there is no support for reduction (or folding) in Google Guava at least (see Issue 218). This is not too hard to add yourself though (not tested):

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;
    }
}

That way you can combine it with Guavas Iterables.transform() like so:

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
    }
}

And then (provided you've import static'ed the relevant classes):

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

Also see this question.


Java is not a functional langugae and often it simpler and faster to just using a plain loop.

You could write something like

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

however IMHO its shorter and simpler to just write.

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

When closures become standard in Java, this will change but for now a loop is often the best way.


Since Java 8 is now out getting a sum on collections is simple:

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

Unfortunately stream is not available on iterables but one can always convert. Arrays are easier:

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


Functional Java has a sum method:

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

Here's an example:

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


You could simply use Lamdaj - a library to manipulate collections in a pseudo-functional and statically typed way:

sum = Lambda.sum(iterable);

It can also do other types of aggregation or you can addd you own Aggregators:

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

See Features for other examples.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜