Вычисление среднего из списка массивов?

Я пытаюсь использовать приведенный ниже код для вычисления среднего значения набора значений, который вводит пользователь, и отображения его в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();
  }

Что не так с кодом?

 Tony Ennis29 мая 2012 г., 01:50
Вы не суммируете метки, вы суммируете индекс массиваi.

Ответы на вопрос(11)

При использованииJava8 Вы можете получить среднее значение из списка следующим образом:

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

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

Преимущество этого состоит в отсутствии движущихся частей. Его можно легко адаптировать для работы со списком других типов объектов, изменив вызов метода map.

Например с двойными:

    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 быть "не присутствующим".

 14 июл. 2017 г., 23:11
в примере 2, зачем mapToDouble, если dblList содержит Doubles?
 26 июн. 2018 г., 03:17
И на самом деле даже это, вы все еще не правы, так какaverage работает только дляprimitive types.
 21 авг. 2015 г., 09:51
упс - никогда не замечал ответ Java8 выше, такой же, как тот, который я дал
 26 июн. 2018 г., 03:11
яdo not думаю, что третий метод работает (используяmapToDouble(BigDecimal::doubleValue).average()). Вы должны использоватьBigDecimal::valueOf вместо.
 30 апр. 2018 г., 12:09
@simpleuser - потому что mapToDouble возвращает DoubleStream, который имеетaverage метод.

Когдаnumber Список не большой, все кажется правильным. Но если это не так, требуется большая осторожность для достиженияcorrectness/accuracy.

приниматьdouble list В качестве примера:

Еслиdouble список не очень большой, вы можете просто попробовать это:

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

Однако, если он находится вне вашего контроля и довольно велик, вы должны обратиться кBigDecimal следующим образом (методы вold answers используя BigDecimal на самом делеwrong):

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

Вложитеtests Я сделал, чтобы продемонстрировать свою точку зрения:

    @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 так же.

Используйте двойное значение для суммы, в противном случае вы делите целочисленное деление и не получите десятичных дробей:

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

или используя потоковый API Java 8:

    return marks.stream().mapToInt(i -> i).average().orElse(0);
 29 мая 2012 г., 02:02
Непосредственно перед возвратом было бы лучше привести к двойному значению, чтобы не возникало никаких ошибок с плавающей запятой, когда отметки представляют собой очень большой список.
 15 сент. 2015 г., 15:58
Что касается API Java 8, каковы необходимые импорт?
 17 сент. 2015 г., 12:52
@eactor В приведенном выше примере дополнительный импорт не требуется.

Вы можете использовать стандартные циклические конструкции или итераторы / списки для того же:

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

Решение Вопроса

Зачем использовать неуклюжий цикл 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;
}
 23 апр. 2014 г., 22:28
Мне нравится Java, но вы должны пропустить функцию C # list.Average (), когда вы делаете это: p
 08 мар. 2016 г., 19:33
Просто быстрое замечание, одна из причин использовать неуклюжий цикл состоит в том, что он намного быстрее, чем так называемый цивилизованный цикл. Для ArrayLists цикл for (int i = 0 ....) примерно в 2 раза быстрее, чем при использовании итератора или подхода for (:), поэтому, хотя он и красивее, он намного медленнее! Один совет, чтобы сделать это еще быстрее, - это кэшировать длину следующим образом: for (int i = 0, len = list.size (); i & lt; len; i ++). Len = list.size () будет выполняться только один раз в начале цикла, и вместо этого будет каждый раз проверяться кешированное значение len.
 29 мая 2012 г., 01:55
+1 почти закончил писать это.
 07 февр. 2013 г., 07:11
Я проверяю, в начале ли марки mark.size () == 0, так как это делит на ноль, если список пуст
 29 мая 2012 г., 01:55
+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();
}

Это решение учитывает:

Handle overflow Do not allocate memory like Java8 stream Do not use slow BigDecimal

Он работает правильно для List, потому что любой список содержит менее 2 ^ 31 int, и его можно использовать как аккумулятор.

PS

Фактически foreach выделяет память - вы должны использовать старый стиль для цикла () в критически важных частях

Вот версия, которая использует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;
}

С помощьюгуайяваСинтаксически упрощается:

Stats.meanOf(numericList);
sum += i;

Вы добавляете индекс; Вы должны добавить фактический элемент вArrayList:

sum += marks.get(i);

Кроме того, чтобы гарантировать, что возвращаемое значение не усечено, принудительно заставьте один операндdouble и измените подпись вашего метода наdouble:

return (double)sum / marks.size();
 29 мая 2012 г., 01:51
@ Цикада: Спасибо! Просто редактировал это в.
 29 мая 2012 г., 01:52
Поскольку он использует список, вы должны использоватьsum += marks.get(i);
List.stream().mapToDouble(a->a).average()
 23 нояб. 2017 г., 18:29
Попробуйте использовать форматирование кода и предоставьте некоторый контекст для вашего ответа. Смотрите другие ответы в качестве примеров.

С Java 8 этонемного проще:

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

Таким образом, ваше среднее значение - Average.getAsDouble ()

return average.isPresent() ? average.getAsDouble() : 0; 
 21 авг. 2015 г., 09:55
average.isPresent() ? average.getAsDouble() : defaultValue может быть упрощено в дальнейшемoptional.orElse( defaultValue )

Ваш ответ на вопрос