Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/373.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 组内组编号的平均值-流_Java_List_Java 8_Java Stream - Fatal编程技术网

Java 组内组编号的平均值-流

Java 组内组编号的平均值-流,java,list,java-8,java-stream,Java,List,Java 8,Java Stream,如何使用流计算组的平均值。下面是我想转换为流解决方案的代码 public static void main(String[] args) { List<Item> items = Arrays.asList( new Item("A", 1.0), new Item("A", 1.0), new Item("B", 1.0) ); System.out.println(averageForGroup(item

如何使用流计算组的平均值。下面是我想转换为流解决方案的代码

public static void main(String[] args) {
    List<Item> items = Arrays.asList(
        new Item("A", 1.0),
        new Item("A", 1.0),
         new Item("B", 1.0)
    );

    System.out.println(averageForGroup(items));
}

public static double  averageForGroup(List<Item> items) {
    Set<String> uniqueGroups = new HashSet<>();
    double sum = 0;
    for (Item i : items) {
        String groupName = i.getGroupName();

        if (!uniqueGroups.contains(groupName)) {
            uniqueGroups.add(groupName);
        }
        sum += i.getValue();
    }

     return sum / uniqueGroups.size();
}
我试过这样的方法:

public static double  averageForGroup2(List<Item> items) {
    return items.stream()
                .collect(Collectors.groupingBy(
                    Item::getGroupName, 
                    Collectors.averagingDouble(Item::getValue)) )
                .entrySet().stream()
                .mapToDouble(entry -> entry.getValue())
                .sum();
}
组2的公共静态双平均值(列表项){ returnitems.stream() .collect(收集器.groupingBy( Item::getGroupName, 收集器.averagingDouble(Item::getValue))) .entrySet().stream() .mapToDouble(条目->条目.getValue()) .sum(); }
但这个方法总结了平均数,所以不是我所期望的。如果可以通过分组恢复求和,则可能会返回异常结果。

您需要类似以下内容:

Map<String, Double> map = items.stream()                       // Stream
    .collect(Collectors.groupingBy(                            // Group to map
                 Item::getGroupName,                           // Key is the groupName
                 Collectors.averagingDouble(Item::getValue))); // Value is the average of values
要使其更具可读性,可以通过两种操作完成:

long distinct = items.stream().map(Item::getGroupName).distinct().count();
double sums = items.stream().mapToDouble(Item::getValue).sum();

System.out.println(sums / distinct);
您可以一次完成,但需要一个自定义收集器…

publicstaticdouble-getAverageByGroups(列表项){
public static double getAverageByGroups(List<Item> items) {
    Map<String, Double> map = Optional.ofNullable(items).orElse(Collections.emptyList()).stream()
                                      .collect(Collectors.groupingBy(Item::getGroupName, Collectors.summingDouble(Item::getValue)));
    return map.isEmpty() ? 0 : map.values().stream().mapToDouble(value -> value).sum() / map.size();
}
Map Map=Optional.ofNullable(items).orElse(Collections.emptyList()).stream() .collect(Collectors.groupby(Item::getGroupName,Collectors.summingDouble(Item::getValue)); 返回map.isEmpty()?0:map.values().stream().mapToDouble(value->value.sum()/map.size(); }

在本例中,
getAverageByGroups
为空的
项返回
0

另一种方法是使用。根据(参见
类平均器
)中的示例,您可以编写自己的类,该类将允许您

  • 收集当前总和和唯一名称
  • 处理每个Item元素以更新唯一名称的总和和集合
  • 在并行处理的情况下,合并该类的其他实例
这样的类可以看起来像

class ItemAverager {
    Set<String> set = new HashSet();
    double sum = 0;

    ItemAverager add(Item item) {
        set.add(item.getGroupName());
        sum += item.getValue();
        return this;
    }

    ItemAverager combine(ItemAverager ia) {
        set.addAll(ia.set);
        sum += ia.sum;
        return this;
    }

    double average() {
        if (set.size() > 0)
            return sum / set.size();
        else
            return 0; //or throw exception
    }
}

这将返回一个
Map
,OP显然对这样的结果不感兴趣。OP可以使用
Map::get
Map
中获得结果。这将是针对单个组的,同样,不是OP之后的结果。一种排序方法可能是
double result=items.stream().collect(Collectors.groupingBy(Item::getGroupName,Collectors.averagingDouble(Item::getValue))).entrySet().stream().mapToDouble(Map.Entry::getValue.average().orElse(Double.NaN);
。即使您的收集器看起来更容易阅读,我还是更愿意选择Eugene回答中建议的第二种方法(易于阅读和实现)。第二种方法比第二种方法好得多…第一种方法相对来说看起来太复杂了。OP不是寻找单个组的平均值,请再次阅读问题。是否发布了预期结果及其背后的一些理由?还有
if(!uniqueGroups.contains(groupName)){uniqueGroups.add(groupName);}
只能是
uniqueGroups.add(groupName);
因为
Set#add
已经检查Set是否包含值。现在我的印象是您可以用
Collectors.summaringdouble(Item::getValue)
替换
Collectors.averagingDouble(Item::getValue)
在你的
平均组2
方法中,去掉剩下的
.entrySet().stream()…
部分。第一条评论:你是对的,它可能写得更简单。第二条评论:是的,它应该平均加倍。我会纠正它。我的第二条评论不是为了澄清问题,而是为了解决问题“如何使用流计算组的平均值”。引用的部分建议您分别计算每个组的平均值,而收集器是这样做的。averagingDouble(Item::getValue)会这样做。但是基于(…)的
loop example这似乎不是您想要的。如果我理解正确,您希望计算所有值的总和,并将其除以唯一组名的数量。如果是这种情况,则您当前的解决方案可能比公认答案中的解决方案更有效。是的,有时似乎可以通过更简单的方法解决一些问题我的意思是代码更简单,至少对我来说是这样。
long distinct = items.stream().map(Item::getGroupName).distinct().count();
double sums = items.stream().mapToDouble(Item::getValue).sum();

System.out.println(sums / distinct);
public static double getAverageByGroups(List<Item> items) {
    Map<String, Double> map = Optional.ofNullable(items).orElse(Collections.emptyList()).stream()
                                      .collect(Collectors.groupingBy(Item::getGroupName, Collectors.summingDouble(Item::getValue)));
    return map.isEmpty() ? 0 : map.values().stream().mapToDouble(value -> value).sum() / map.size();
}
class ItemAverager {
    Set<String> set = new HashSet();
    double sum = 0;

    ItemAverager add(Item item) {
        set.add(item.getGroupName());
        sum += item.getValue();
        return this;
    }

    ItemAverager combine(ItemAverager ia) {
        set.addAll(ia.set);
        sum += ia.sum;
        return this;
    }

    double average() {
        if (set.size() > 0)
            return sum / set.size();
        else
            return 0; //or throw exception
    }
}
List<Item> items = Arrays.asList(
        new Item("A", 1.0),
        new Item("A", 3.0),
        new Item("B", 1.0)
);

double avrg = items
        .stream()
        .collect(ItemAverager::new,
                 ItemAverager::add, 
                 ItemAverager::combine
        ).average();      // `collect` will return ItemAverager
                          // on which we can call average()

System.out.println(avrg); // Output: 2.5 
                          // (since 1+3+1 = 5 and there are only two groups 5/2 = 2.5)
public static double  averageForGroup(List<Item> items) {
    Set<String> uniqueGroups = new HashSet<>();
    double sum = 0;
    for (Item item : items) {
        uniqueGroups.add(item.getGroupName());
        sum += item.getValue();
    }
    return sum / uniqueGroups.size();
}