una suma promedio notas matriz matrices los filas elementos con columnas calcular arreglos alumnos java arrays average

suma - promedio de columnas en java



¿Cálculo del promedio de una lista de matriz? (11)

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. Digamos, un usuario ingresa 7, 4 y 5, el programa muestra 1 como el promedio cuando debería mostrar 5.3

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

¿Qué está mal con el código?


¿Por qué utilizar un bucle for foroso con un índice cuando tiene el bucle for 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; }


Aquí una versión que usa BigDecimal vez 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; }


Con Java 8 es un poco más fácil :

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

Por lo tanto, su valor promedio es average.getAsDouble ()

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


Cuando la lista de números no es grande, todo parece estar bien. Pero si no lo es, se requiere gran precaución para lograr la corrección / precisión .

Tome la lista doble como ejemplo:

Si la lista doble no es muy grande, puedes intentar esto:

doubles.stream().mapToDouble(d -> d).average().orElse(0.0);

Sin embargo, si está fuera de su control y es bastante grande, debe recurrir a BigDecimal de la siguiente manera (los métodos en las respuestas antiguas que usan BigDecimal en realidad son incorrectos ):

doubles.stream().map(BigDecimal::valueOf).reduce(BigDecimal.ZERO, BigDecimal::add) .divide(BigDecimal.valueOf(doubles.size())).doubleValue();

Adjunte las pruebas que realicé para demostrar mi punto:

@Test public void testAvgDouble() { assertEquals(5.0, getAvgBasic(Stream.of(2.0, 4.0, 6.0, 8.0)), 1E-5); List<Double> doubleList = new ArrayList<>(Arrays.asList(Math.pow(10, 308), Math.pow(10, 308), Math.pow(10, 308), Math.pow(10, 308))); // Double.MAX_VALUE = 1.7976931348623157e+308 BigDecimal doubleSum = BigDecimal.ZERO; for (Double d : doubleList) { doubleSum = doubleSum.add(new BigDecimal(d.toString())); } out.println(doubleSum.divide(valueOf(doubleList.size())).doubleValue()); out.println(getAvgUsingRealBigDecimal(doubleList.stream())); out.println(getAvgBasic(doubleList.stream())); out.println(getAvgUsingFakeBigDecimal(doubleList.stream())); } private double getAvgBasic(Stream<Double> doubleStream) { return doubleStream.mapToDouble(d -> d).average().orElse(0.0); } private double getAvgUsingFakeBigDecimal(Stream<Double> doubleStream) { return doubleStream.map(BigDecimal::valueOf) .collect(Collectors.averagingDouble(BigDecimal::doubleValue)); } private double getAvgUsingRealBigDecimal(Stream<Double> doubleStream) { List<Double> doubles = doubleStream.collect(Collectors.toList()); return doubles.stream().map(BigDecimal::valueOf).reduce(BigDecimal.ZERO, BigDecimal::add) .divide(valueOf(doubles.size()), BigDecimal.ROUND_DOWN).doubleValue(); }

En cuanto a Integer o Long , de forma correspondiente puede usar BigInteger manera similar.


Método de cálculo correcto y rápido 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 de manija
  • No asigne memoria como la secuencia de Java8
  • No use BigDecimal lento

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

PD

En realidad, para asignar memoria: debe usar el estilo antiguo para () ciclo en partes críticas.


Puede usar construcciones de bucle estándar o iterador / listiterator para el 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 usa Java 8, puede usar las operaciones de Stream o IntSream para lo mismo:

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

Referencia: Cálculo promedio de la lista de arrays


Si usa Java8 , 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().orElse(0.0);

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().orElse(0.0);

NÓTESE BIEN. mapToDouble es necesario porque devuelve un DoubleStream que tiene un método average , mientras que el uso del map no lo hace.

o BigDecimales:

@Test public void bigDecimalListAveragedCorrectly() { 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().orElse(0.0); assertEquals(2.55, average, 0.000001); }

El uso de orElse(0.0) elimina los problemas con el objeto opcional devuelto del average que no está presente.


Usa un doble para la suma, de lo contrario estarás haciendo una división entera y no obtendrás ningún 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 usando la API de flujo de Java 8:

return marks.stream().mapToInt(i -> i).average().orElse(0);


Usando Guava , se simplifica sintácticamente:

Stats.meanOf(numericList);


List.stream().mapToDouble(a->a).average()


sum += i;

Estás agregando el índice; debería agregar el elemento real en ArrayList :

sum += marks.get(i);

Además, para garantizar que el valor de retorno no se trunque, fuerce un operando a double y cambie la firma de su método al double :

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