2012-05-28 21 views
32

Estoy tratando de usar el siguiente código para calcular el promedio de un conjunto de valores que un usuario ingresa y mostrar en un jTextArea pero no funciona correctamente. Por ejemplo, un usuario introduce 7, 4 y 5, el programa muestra 1 como el promedio cuando debería mostrar 5,3¿Cálculo promedio de una lista de matriz?

ArrayList <Integer> marks = new ArrayList(); 
    Collections.addAll(marks, (Integer.parseInt(markInput.getText()))); 

    private void analyzeButtonActionPerformed(java.awt.event.ActionEvent evt) { 
     analyzeTextArea.setText("Class average:" + calculateAverage(marks)); 
    } 

    private int calculateAverage(List <Integer> marks) { 
     int sum = 0; 
     for (int i=0; i< marks.size(); i++) { 
      sum += i; 
     } 
     return sum/marks.size(); 
    } 

Lo que está mal con el código?

+5

No estás sumando marcas, estás sumando los índice de matriz 'i'. –

Respuesta

57

¿Por qué utilizar un bucle torpe para un índice cuando tiene el bucle forzado mejorado?

private double calculateAverage(List <Integer> marks) { 
    Integer sum = 0; 
    if(!marks.isEmpty()) { 
    for (Integer mark : marks) { 
     sum += mark; 
    } 
    return sum.doubleValue()/marks.size(); 
    } 
    return sum; 
} 
+23

+1 Este es un ciclo civilizado para un tiempo más civilizado. No es tan torpe ni aleatorio como un bláster. –

+0

+1 estaba a punto de terminar de escribir esto. – n00begon

+5

Verificaría si marks.size() == 0 al principio, ya que esto se dividirá por cero si la lista está vacía – Axarydax

9
sum += i; 

Está agregando el índice; se debe agregar el elemento real en el ArrayList:

sum += marks.get(i); 

Asimismo, para garantizar el valor de retorno no se trunca, la fuerza de un operando a double y cambiar su método de firma de double:

return (double)sum/marks.size(); 
+0

@Cicada: ¡Gracias! Solo estaba editando eso. – Ryan

+3

Como está usando una lista, debe usar 'suma + = marcas.get (i);' – jahroy

10

Use un doble para la suma, de lo contrario se está haciendo una división entera y usted no recibirá decimales:

private double calculateAverage(List <Integer> marks) { 
    if (marks == null || marks.isEmpty()) { 
     return 0; 
    } 

    double sum = 0; 
    for (Integer mark : marks) { 
     sum += mark; 
    } 

    return sum/marks.size(); 
} 

o utilizando el Java 8 API de transmisión:

+0

Sería más limpio castear a un doble justo antes de regresar para que no tenga ningún flotante los errores puntuales aparecen cuando las marcas son una lista muy grande. – n00begon

+0

con respecto a la API de Java 8 ¿cuáles son las importaciones necesarias? – eactor

+0

@eactor En el ejemplo anterior, no es necesaria ninguna importación adicional. –

40

Con Java 8 es a bit easier:

OptionalDouble average = marks 
      .stream() 
      .mapToDouble(a -> a) 
      .average(); 

lo tanto su valor medio es average.getAsDouble()

return average.isPresent() ? average.getAsDouble() : 0; 
+13

' average.isPresent()? average.getAsDouble(): defaultValue' se puede simplificar más a 'optional.orElse (defaultValue)' –

0

Aquí una versión que utiliza BigDecimal en lugar de double:

public static BigDecimal calculateAverage(final List<Integer> values) { 
    int sum = 0; 
    if (!values.isEmpty()) { 
     for (final Integer v : values) { 
      sum += v; 
     } 
     return new BigDecimal(sum).divide(new BigDecimal(values.size()), 2, RoundingMode.HALF_UP); 
    } 
    return BigDecimal.ZERO; 
} 
1

Calcular la media manera correcta y rápida para List<Integer>:

private double calculateAverage(List<Integer> marks) { 
    long sum = 0; 
    for (Integer mark : marks) { 
     sum += mark; 
    } 
    return marks.isEmpty()? 0: 1.0*sum/marks.size(); 
} 

Esta solución tiene en cuenta:

  • desbordamiento manija
  • No asignar memoria como corriente Java8
  • No usar BigDecimal lenta

Funciona correctamente para List, porque cualquier lista contiene menos de 2^31 int, y es posible utilizar long como acumulador.

PS

En realidad forEach asignar memoria - que debe utilizar al viejo estilo para el ciclo() en la misión partes críticas

12

Si se utiliza Java8 se puede obtener el promedio de los valores de una lista de la siguiente manera:

List<Integer> intList = Arrays.asList(1,2,2,3,1,5); 

    Double average = intList.stream().mapToInt(val -> val).average().getAsDouble(); 

Esto tiene la ventaja de no tener partes móviles. Se puede adaptar fácilmente para trabajar con una Lista de otros tipos de objetos cambiando la llamada al método del mapa.

Por ejemplo, con dobles:

List<Double> dblList = Arrays.asList(1.1,2.1,2.2,3.1,1.5,5.3); 
    Double average = dblList.stream().mapToDouble(val -> val).average().getAsDouble(); 

o BigDecimals:

List<BigDecimal> bdList = Arrays.asList(valueOf(1.1),valueOf(2.1),valueOf(2.2),valueOf(3.1),valueOf(1.5),valueOf(5.3)); 
    Double average = bdList.stream().mapToDouble(BigDecimal::doubleValue).average().getAsDouble(); 
+0

¡Uy! Nunca noté la respuesta de Java8 anterior que es la misma que la que di – robjwilkins

+0

en el ejemplo 2, ¿por qué es necesario MapToDouble cuando dblList contiene Dobles? – simpleuser

1

Uso Guava, se pone sintácticamente simplificada:

Stats.meanOf(numericList); 
1

Usted puede usar construcciones de bucle estándar o iterador/listiterator para lo mismo:

List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8); 
double sum = 0; 
Iterator<Integer> iter1 = list.iterator(); 
while (iter1.hasNext()) { 
    sum += iter1.next(); 
} 
double average = sum/list.size(); 
System.out.println("Average = " + average); 

Si el uso de Java 8, puede utilizar las operaciones de rutas o IntSream para el mismo:

OptionalDouble avg = list.stream().mapToInt(Integer::intValue).average(); 
System.out.println("Average = " + avg.getAsDouble()); 

Referencia: Calculating average of arraylist

0
List.stream().maptodouble(a->a).Average() 
+0

Trate de usar el formato del código y proporcione un contexto para su respuesta. Vea las otras respuestas como ejemplos. – hidralisk

Cuestiones relacionadas