Итерируемая сумма в 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);
}
Ответы
Ответ 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 для других примеров.
Ответ 5
Функциональная Java имеет метод суммирования:
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));