Подтвердить что ты не робот

Итерируемая сумма в Java?

Есть ли библиотека, которая делает это:

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);
}
4b9b3361

Ответ 1

В основном есть две полезные библиотеки, которые могут помочь в этом; Google Guava и Коллекции сообщества Apache.

То, что вы пытаетесь сделать, это в основном две операции, первое сопоставление, затем сокращение. Я никогда не использовал Commons Collections в какой-либо мере, поэтому я не могу больше рассказать об этом, но я знаю, что в Google Guava нет поддержки для сокращения (или сворачивания) (см. Проблема 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
    }
}

И затем (если вы импортируете static'ed соответствующие классы):

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

Также см. этот вопрос.

Ответ 2

Java не является функциональным langugae и часто проще и быстрее, просто используя простой цикл.

Вы можете написать что-то вроде

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

однако IMHO его короче и проще просто написать.

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

Когда закрытие станет стандартным в Java, это изменится, но на данный момент цикл является лучшим способом.

Ответ 3

Так как Java 8 теперь получает сумму в коллекциях, это просто:

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

К сожалению, поток не доступен в iterables, но он всегда может конвертироваться. Массивы проще:

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

Ответ 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 для других примеров.