Calcul de la moyenne d'une liste de tableau?

Je suis en train d'utiliser le code ci-dessous pour calculer la moyenne d'un ensemble de valeurs qu'un utilisateur saisit et l'afficher dans un jTextArea, mais il ne fonctionne pas correctement. Par exemple, un utilisateur entre 7, 4 et 5, le programme affiche 1 comme moyenne quand il doit afficher 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();
  }

Quel est le problème avec le code?

38
demandé sur giannis christofakis 2012-05-29 03:49:14

11 réponses

Pourquoi utiliser une boucle for maladroite avec un index lorsque vous avez la boucle for améliorée?

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;
}
59
répondu Jeshurun 2013-06-21 20:34:37

Avec Java 8, il est un peu plus facile:

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

Ainsi votre valeur moyenne est moyenne.getAsDouble ()

return average.isPresent() ? average.getAsDouble() : 0; 
50
répondu Mariana 2015-06-24 08:46:32

Si vous utilisez Java8, vous pouvez obtenir la moyenne des valeurs dans une Liste comme suit:

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

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

Ceci a l'avantage de ne pas avoir de pièces mobiles. Il peut être facilement adapté pour travailler avec une liste d'autres types d'objets en changeant l'appel de méthode map.

Par exemple avec des Doubles:

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

NB. mapToDouble est requis car il renvoie un DoubleStream qui a une méthode average, alors que l'utilisation de map ne le fait pas.

Ou BigDecimals:

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

Utilisation orElse(0.0) supprime les problèmes avec l'objet optionnel renvoyé du average étant 'absent'.

19
répondu robjwilkins 2018-06-26 09:59:58

Utilisez un double pour la somme, sinon vous faites une division entière et vous n'obtiendrez aucune décimale:

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

Ou en utilisant L'API Java 8 stream:

    return marks.stream().mapToInt(i -> i).average().orElse(0);
12
répondu Emmanuel Bourg 2013-11-28 09:27:51
sum += i;

Vous ajoutez l'index; vous devriez ajouter l'élément réel dans le ArrayList:

sum += marks.get(i);

Aussi, pour vous assurer que la valeur de retour n'est pas tronquée, forcez un opérande à double et changez votre signature de méthode à double:

return (double)sum / marks.size();
10
répondu Ry- 2012-05-28 23:50:40

En utilisant Goyave , il est syntaxiquement simplifié:

Stats.meanOf(numericList);
2
répondu Sayan Pal 2017-02-20 15:39:04
List.stream().mapToDouble(a->a).average()
2
répondu Dinesh Kumar 2018-06-26 05:24:26

Moyen Correct et rapide de calculer la moyenne pour 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();
}

Cette solution prend en compte:

  • gérer le débordement
  • n'allouez pas de mémoire comme Java8 stream
  • N'utilisez pas lent BigDecimal

Cela fonctionne coorectly pour List, car toute liste contient moins de 2^31 int, et il est possible d'utiliser long comme accumulateur.

PS

En fait, foreach alloue de la mémoire - vous devez utiliser l'ancien style pour le cycle () dans les parties critiques

1
répondu sibnick 2015-08-14 04:59:06

Vous pouvez utiliser des constructions en boucle standard ou iterator / listiterator pour la même chose:

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 vous utilisez Java 8, Vous pouvez utiliser des opérations Stream ou IntSream pour la même chose:

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

Référence : Calcul de la moyenne de l'arraylist

1
répondu Sekhar Ray 2017-08-04 20:05:24

Ici une version qui utilise BigDecimal au lieu 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;
}
0
répondu yglodt 2015-07-09 09:37:21

Lorsque la listeNombre n'est pas grande, tout semble juste. Mais si ce n'est pas le cas, une grande prudence est requise pour atteindre exactitude/précision.

Prendre double liste exemple:

Si la liste double n'est pas assez grande, vous pouvez simplement essayer ceci:

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

Cependant, si c'est hors de votre contrôle et assez grand, vous devez vous tourner vers BigDecimal comme suit (les méthodes dans les anciennes réponses utilisant BigDecimal sont en fait faux):

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

Joindre les tests que j'ai effectués pour démontrer mon point:

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

Comme pour Integer ou Long, Vous pouvez également utiliser BigInteger de la même manière.

0
répondu Hearen 2018-06-26 11:58:59