我正在尝试使用以下代码来计算用户输入的一组值的平均值,并将其显示在jTextArea
中,但它无法正常工作。比如,用户输入7,4和5,程序显示1作为应显示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();
}
代码有什么问题?
答案 0 :(得分:63)
为什么在使用增强的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;
}
答案 1 :(得分:55)
使用Java 8,它是a bit easier:
OptionalDouble average = marks
.stream()
.mapToDouble(a -> a)
.average();
因此,您的平均值为average.getAsDouble()
return average.isPresent() ? average.getAsDouble() : 0;
答案 2 :(得分:24)
如果使用 Java8 ,您可以按如下方式获取List中值的平均值:
List<Integer> intList = Arrays.asList(1,2,2,3,1,5);
Double average = intList.stream().mapToInt(val -> val).average().orElse(0.0);
这具有没有活动部件的优点。通过更改map方法调用,可以轻松地调整它以使用其他类型对象的List。
例如双打:
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是必需的,因为它返回一个具有average
方法的DoubleStream,而使用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
“不存在”所返回的Optional对象的问题。
答案 3 :(得分:13)
使用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();
}
或使用Java 8流API:
return marks.stream().mapToInt(i -> i).average().orElse(0);
答案 4 :(得分:10)
sum += i;
您正在添加索引;您应该在ArrayList
:
sum += marks.get(i);
此外,为了确保不截断返回值,请强制一个操作数到double
并将方法签名更改为double
:
return (double)sum / marks.size();
答案 5 :(得分:2)
使用Guava,语法简化:
Stats.meanOf(numericList);
答案 6 :(得分:2)
List.stream().mapToDouble(a->a).average()
答案 7 :(得分: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();
}
此解决方案考虑到:
它对List有共同作用,因为任何列表都包含少于2 ^ 31 int,并且可以使用long作为累加器。
PS
实际上foreach分配内存 - 你应该在关键任务部分使用旧式的()循环
答案 8 :(得分:1)
您可以使用标准循环结构或iterator / listiterator:
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());
答案 9 :(得分: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;
}
答案 10 :(得分:0)
当数字列表不大时,一切似乎都正确。但是,如果不是这样,则需要非常小心以实现正确性/准确性。
以双重列表为例:
如果 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
。