web-dev-qa-db-fra.com

Calculer la moyenne d'une liste de tableaux?

J'essaie d'utiliser le code ci-dessous pour calculer la moyenne d'un ensemble de valeurs saisies par un utilisateur et l'afficher dans une jTextArea, mais cela ne fonctionne pas correctement. Supposons qu'un utilisateur entre 7, 4 et 5, le programme affiche 1 comme moyenne, alors qu'il devrait 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?

41
user1419306

Pourquoi utiliser une boucle for maladroite avec un index alors que vous disposez de 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;
}
62
Jeshurun

Avec Java 8 c'est un peu plus facile :

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

Ainsi, votre valeur moyenne est average.getAsDouble ()

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

Si vous utilisez Java8 vous pouvez obtenir la moyenne des valeurs d’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);

Cela a l'avantage de ne pas avoir de pièces mobiles. Il peut être facilement adapté à une liste d’autres types d’objets en modifiant l’appel de la méthode map. 

Par exemple avec les 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 retourne un DoubleStream qui a une méthode average, contrairement à map

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

l'utilisation de orElse(0.0) supprime les problèmes liés à la non-présence de l'objet optionnel retourné par average.

23
robjwilkins

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 de flux Java 8:

    return marks.stream().mapToInt(i -> i).average().orElse(0);
13
Emmanuel Bourg
sum += i;

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

sum += marks.get(i);

De plus, pour vous assurer que la valeur de retour n'est pas tronquée, forcez un opérande sur double et modifiez la signature de votre méthode en double:

return (double)sum / marks.size();
10
Ry-

En utilisant Guava , la syntaxe est simplifiée:

Stats.meanOf(numericList);
2
Sayan Pal
List.stream().mapToDouble(a->a).average()
2
Dinesh Kumar

Méthode de calcul correcte et rapide 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:

  • Trop-plein de la poignée
  • Ne pas allouer de mémoire comme un flux Java8 
  • Ne pas utiliser BigDecimal lent

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

PS

En fait, pour chaque allocation de mémoire, vous devez utiliser l'ancien style pour le cycle () dans les parties critiques

1
sibnick

Vous pouvez utiliser des constructions en boucle standard ou un itérateur/listiterateur 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 les 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 d'arrayliste

1
Sekhar Ray

Voici 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
yglodt

Lorsque la liste number n'est pas grande, tout semble parfait. Mais si ce n'est pas le cas, une grande prudence est requise pour obtenir exactitude/exactitude

Prenons double liste à titre d'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 gros, vous devez vous tourner vers BigDecimal comme suit (les méthodes dans les anciennes réponses utilisant BigDecimal sont en fait incorrectes ):

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

Joignez les tests j’ai réalisé pour démontrer mon propos:

    @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 ce qui concerne Integer ou Long, vous pouvez également utiliser BigInteger de la même manière. 

0
Hearen