64

以下のコードを使用して、ユーザーが入力して表示する一連の値の平均を計算しようとしていますが、jTextArea正しく機能しません。たとえば、ユーザーが7、4、および5を入力すると、プログラムは5.3を表示する必要があるときに平均として1を表示します。

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

コードの何が問題になっていますか?

4

11 に答える 11

86

Java 8を使用すると、少し簡単になります。

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

したがって、平均値はaverage.getAsDouble()です。

return average.isPresent() ? average.getAsDouble() : 0; 
于 2015-06-24T08:46:32.117 に答える
77

拡張されたforループがあるのに、なぜインデックス付きの不器用なforループを使用するのですか?

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

更新:他のいくつかがすでに指摘しているように、これはJava8以降でStreamsを使用するとはるかに簡単になります。

private double calculateAverage(List <Integer> marks) {
    return marks.stream()
                .mapToDouble(d -> d)
                .average()
                .orElse(0.0)
}
于 2012-05-28T23:54:19.097 に答える
41

Java8以降では、次のようにリストから値の平均を取得できます。

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

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

これには、可動部品がないという利点があります。mapメソッド呼び出しを変更することにより、他のタイプのオブジェクトのリストを操作するように簡単に適合させることができます。

たとえば、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が必要なのは、メソッドを持つDoubleStreamを返すのaverageに対し、使用する場合はそうでmapはないためです。

または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);
}

を使用すると、「存在しない」orElse(0.0)から返されるオプションオブジェクトの問題が解消されますaverage

于 2015-08-21T07:47:16.190 に答える
18

合計にdoubleを使用します。そうしないと、整数除算を実行し、小数を取得できません。

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

またはJava8ストリームAPIを使用します。

    return marks.stream().mapToInt(i -> i).average().orElse(0);
于 2012-05-28T23:50:49.013 に答える
11
sum += i;

インデックスを追加しています。ArrayList:に実際のアイテムを追加する必要があります。

sum += marks.get(i);

また、戻り値が切り捨てられないようにするには、1つのオペランドを強制的doubleに変更し、メソッドのシグネチャをdouble次のように変更します。

return (double)sum / marks.size();
于 2012-05-28T23:50:40.330 に答える
6

Guavaを使用すると、構文が単純化されます。

Stats.meanOf(numericList);
于 2017-02-20T15:39:04.413 に答える
2
List.stream().mapToDouble(a->a).average()
于 2017-11-23T17:14:06.250 に答える
2

が多くない場合は、すべてが適切に見えます。しかし、そうでない場合は、正確さを達成するために細心の注意が必要です。

例としてdoubleを取り上げます。

他の人が言ったように、それが大きくない場合は、これを簡単に試すことができます:

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

ただし、それが制御不能で非常に大きい場合は、次のようにBigDecimalを使用する必要があります(BigDecimalを使用した古い回答の方法は実際には間違っています)。

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

私の主張を実証するために実行したテストを同封してください。

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

Integerまたは、対応して同様にLong使用できますBigInteger

于 2018-06-26T01:20:05.617 に答える
1

正確で高速な方法で平均を計算し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();
}

このソリューションは以下を考慮に入れます:

  • オーバーフローを処理する
  • Java8ストリームのようにメモリを割り当てないでください
  • 遅いBigDecimalを使用しないでください

どのリストにも2^31 int未満しか含まれておらず、アキュムレータとして長く使用できるため、Listに対して正しく機能します。

PS

実際にforeachはメモリを割り当てます-ミッションクリティカルな部分では古いスタイルのfor()サイクルを使用する必要があります

于 2015-08-14T04:59:06.750 に答える
1

同じために、標準のループ構造またはイテレータ/リスティテレータを使用できます。

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

Java 8を使用している場合は、同じ操作に対してStreamまたはIntSream操作を使用できます。

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

参照:arraylistの平均の計算

于 2017-08-04T20:05:24.107 に答える
0

BigDecimalここでは、の代わりにを使用するバージョン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;
}
于 2015-07-09T09:37:21.930 に答える