Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/303.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
按一个字段分组,并计算Java8中的非空字段_Java_Collections_Java 8_Java Stream - Fatal编程技术网

按一个字段分组,并计算Java8中的非空字段

按一个字段分组,并计算Java8中的非空字段,java,collections,java-8,java-stream,Java,Collections,Java 8,Java Stream,我尝试使用Java8特性 我有一节课 @Data @NoArgsConstructor @AllArgsConstructor class User { private String pId; private String uId; private String price; } 我有一个列表,我尝试按pId分组,并计算非空的uId和price。例如: List<User> list = Arrays.asList( new User ("

我尝试使用Java8特性

我有一节课

@Data
@NoArgsConstructor
@AllArgsConstructor
class User {
    private String pId;
    private String uId;
    private String price;
}
我有一个列表,我尝试按
pId
分组,并计算非空的
uId
price
。例如:

List<User> list =
Arrays.asList(
    new User ("p1", "u1", null),
    new User ("p1", "u2", "a"),
    new User ("p2", null, "b"),
    new User ("p2", null, "c"),
    new User ("p3", "u4", "d")
);
我试着跟在后面

Map<String, Map<Object, Long>> collect =
    list.stream()
        .collect(
            Collectors.groupingBy(
                User ::getPId,
                Collectors.groupingBy(f -> f.getUId(), Collectors.counting())));

因为我是java新手,所以我要努力完成它,我尽了最大的努力。可以删除空字段并计数吗?

您可以尝试下面的解决方案吗?它将提供正确的输出:

import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;

public class Main {

    public static void main(String[] args) {
        List<User> list =
                Arrays.asList(
                    new User ("p1", "u1", null),
                    new User ("p1", "u2", "a"),
                    new User ("p2", null, "b"),
                    new User ("p2", null, "c"),
                    new User ("p3", "u4", "d")
                );

        Set<Stat> set = list.stream().map(s -> new Stat(s.getPId(), 0, 0)).collect(Collectors.toSet());
        set = set.stream().map(s -> updateCounts(list, s.getPId())).collect(Collectors.toSet());

        System.out.println(set);
    }

    public static Stat updateCounts(List<User> list, String pId) {
        Long uCount = list.stream().filter(s -> pId.equals(s.getPId()) && Objects.nonNull(s.getUId()))
            .collect(Collectors.counting());

        Long priceCount = list.stream().filter(s -> pId.equals(s.getPId()) && Objects.nonNull(s.getPrice()))
                .collect(Collectors.counting());
        return new Stat(pId, Integer.valueOf(uCount+""), Integer.valueOf(priceCount+""));
    }
}
导入java.util.array;
导入java.util.List;
导入java.util.Objects;
导入java.util.Set;
导入java.util.stream.collector;
公共班机{
公共静态void main(字符串[]args){
列表=
Arrays.asList(
新用户(“p1”、“u1”、null),
新用户(“p1”、“u2”、“a”),
新用户(“p2”,空,“b”),
新用户(“p2”,空,“c”),
新用户(“p3”、“u4”、“d”)
);
Set Set=list.stream().map(s->newstat(s.getPId(),0,0)).collect(Collectors.toSet());
set=set.stream().map(s->updateCounts(list,s.getPId()).collect(Collectors.toSet());
系统输出打印项次(套);
}
公共静态统计更新计数(列表、字符串pId){
Long uCount=list.stream().filter(s->pId.equals(s.getPId())&&Objects.nonNull(s.getUId())
.collect(collector.counting());
Long priceCount=list.stream().filter(s->pId.equals(s.getPId())&&Objects.nonNull(s.getPrice())
.collect(collector.counting());
返回新的Stat(pId,Integer.valueOf(uCount+“”),Integer.valueOf(priceCount+“”);
}
}

我建议以下解决方案。它对每个组使用缩减操作,并且需要在
Stat
类中添加一些内容,以便代码看起来整洁一些

@数据
@诺尔格构装师
@AllArgsConstructor
类统计{
私有字符串pId;
私有整数uCount;
私有整数价格计数;
公共静态Stat init(){
返回新的Stat(null,Integer.valueOf(0),Integer.valueOf(0));
}
公共价值(统计){
this.uCount+=(s.uCount!=null)?s.uCount:0;
this.priceCount+=(s.priceCount!=null)?s.priceCount:0;
}
公共静态统计mapToStat(用户){
stats=newstat(user.getPId(),0,0);
if(user.getUid()!=null){
s、 uCount++;
}
if(user.getPrice()!=null){
s、 priceCount++;
}
}
}
现在,流操作:

return list.stream()//返回的列表
.collect(Collectors.groupingBy(User::getPId,Collectors.reduction)(new Stat(),Stat::mapToStat,(s1,s2)->{
//您也可以将下面的部分移动到Stat中的方法
Stat s=Stat.init();
s、 setPId(s1.getPId());
s、 incValue(s1);
s、 inc值(s2);
如果(s1.getPId()==null){
s、 setPId(s2.getPId());
}
返回s;
})))
.values()
.stream()
.collect(Collectors.toList());
我将把优化/清理部分留给您:-)

此外,请查看此问题/答案。这也是一个非常相似但略有不同的场景。
Java 12+解决方案

通过使用
teeing
采集器和
filtering
可以执行以下操作:

Map<String, Detail> result = list.stream()
       .collect(Collectors.groupingBy(User::getpId, Collectors.teeing(
           Collectors.filtering(u -> u.getuId() != null, Collectors.counting()),
           Collectors.filtering(u -> u.getPrice() != null, Collectors.counting()),
           (uCount, priceCount) -> new Detail(uCount, priceCount)
        )));
输出:

{ p1=详细信息{uCount=2,priceCount=1}, p2=详细信息{uCount=0,priceCount=2}, p3=详细信息{uCount=1,priceCount=1} }


您可以使用
减少
操作:

导入静态java.util.stream.collector.*;
函数getStatFromUser=
u->new Stat(u.getpId(),
u、 getuId()==null?0:1,
u、 getPrice()==null?0:1);
二进制运算符addStats=
(o1,o2)->o1(标识元素)的第一个元素pId的新Stat(//Imp to getpId from o2)将为“”
o2.getpId(),
o1.getuCount()+o2.getuCount(),
o1.getPriceCount()+o2.getPriceCount());
映射结果=
list.stream().collect(
groupingBy(用户::getpId,
减少(
新统计数据(“”),
u->statFromUser.apply(u),
(o1,o2)->addStats.apply(o1,o2));
对于讨论中的测试用例,输出应该如下所示:

{
p1={pId=p1,uCount=2,priceCount=1},
p2={pId=p2,uCount=0,priceCount=2},
p3={pId=p3,uCount=1,priceCount=1}
}
要获得预期的输出,可以调用
collecting,然后在
groupingBy
上调用

对象结果=
list.stream()
.收集(
收集然后(
groupingBy(用户::getpId,
减少(新产量(“”),
u->outputFromUser.apply(u),
(o1,o2)->添加组。应用(o1,o2)),
m->m.values());
上述构造的输出为:

[
输出{pId=p1,uCount=2,priceCount=1},
输出{pId=p2,uCount=0,priceCount=2},
输出{pId=p3,uCount=1,priceCount=1}
]
编辑1:

另一种解决方案是使用
toMap

对象结果=
list.stream()
.收集(
收集然后(
toMap(用户::getpId,
u->outputFromUser.apply(u),
(o1,o2)->添加组。应用(o1,o2)),
m->m.values());

做这样的工作可能会干净得多。@Naman是的。上面的
减少
部分涉及不必要的
Stat
对象创建为什么不在问题中使用
Stat
类而不是import java.util.Arrays; import java.util.List; import java.util.Objects; import java.util.Set; import java.util.stream.Collectors; public class Main { public static void main(String[] args) { List<User> list = Arrays.asList( new User ("p1", "u1", null), new User ("p1", "u2", "a"), new User ("p2", null, "b"), new User ("p2", null, "c"), new User ("p3", "u4", "d") ); Set<Stat> set = list.stream().map(s -> new Stat(s.getPId(), 0, 0)).collect(Collectors.toSet()); set = set.stream().map(s -> updateCounts(list, s.getPId())).collect(Collectors.toSet()); System.out.println(set); } public static Stat updateCounts(List<User> list, String pId) { Long uCount = list.stream().filter(s -> pId.equals(s.getPId()) && Objects.nonNull(s.getUId())) .collect(Collectors.counting()); Long priceCount = list.stream().filter(s -> pId.equals(s.getPId()) && Objects.nonNull(s.getPrice())) .collect(Collectors.counting()); return new Stat(pId, Integer.valueOf(uCount+""), Integer.valueOf(priceCount+"")); } }
Map<String, Detail> result = list.stream()
       .collect(Collectors.groupingBy(User::getpId, Collectors.teeing(
           Collectors.filtering(u -> u.getuId() != null, Collectors.counting()),
           Collectors.filtering(u -> u.getPrice() != null, Collectors.counting()),
           (uCount, priceCount) -> new Detail(uCount, priceCount)
        )));
class Detail{
  private long uCount;
  private long priceCount;
}