2011-01-21 17 views
12

¿Existe una biblioteca que hace esto:Suma Iterable en 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); 
} 

Respuesta

10

Hay básicamente dos bibliotecas útiles que pueden ayudar con esto; Google Guava y Apache Commons Collections.

Lo que estás tratando de hacer es básicamente dos operaciones, primero mapeo, luego reducción. Nunca he usado Commons Collections en modo alguno, así que no puedo contarle más sobre eso, pero sé que no hay soporte para reducción (o plegado) en Google Guava al menos (consulte Issue 218). Esto no es demasiado difícil añadir a sí mismo, aunque (no probado):

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

De esta manera se puede combinar con guayabas Iterables.transform(), así:

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

Y luego (se proporciona' ve importación static'ed las clases apropiadas):

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

también ver this question.

+0

¿Podría corregir su ejemplo? Me sale 'El método aplicar (A) en el tipo Función no es aplicable para los argumentos (B, A)' en la línea fun.apply(). –

+0

Quizás. Probablemente no.La respuesta es de 5 años, solo usa Java 8 streams :) –

9

Java no es una languga funcional y, a menudo, es más simple y más rápido que simplemente usar un bucle simple.

Se podría escribir algo así como

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

sin embargo en mi humilde opinión la más corta y más fácil de simplemente escribir.

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

Cuando el cierre sea estándar en Java, esto va a cambiar, pero por ahora un bucle es a menudo la mejor manera.

+1

Solo recuerda: 'más corto! = Más fácil de leer', un sesgo cognitivo del que la mayoría de los programadores no están conscientes. –

+0

@ Sridhar-Sarnobat estuvo de acuerdo en que es algo de lo que hay que tener cuidado cuando se usan lambdas lambda, especialmente angostas. por ejemplo 'a -> b -> a> b' es corto pero no muy claro. –

3

Simplemente podría utilizar Lamdaj - una biblioteca para manipular colecciones en un pseudo-funcional y tipos estáticos manera:

sum = Lambda.sum(iterable); 

También puede hacer otros tipos de agregación o puede addd es el propietario agregadores:

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

Ver Features para otros ejemplos.

7

Desde Java 8 está ahora fuera recibiendo una suma de colecciones es simple:

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

Desafortunadamente corriente no está disponible en iterables pero uno siempre se puede convertir. Las matrices son más fáciles:

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