加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 编程开发 > Java > 正文

java – 使用Collection.stream通过特定属性进行动态分组

发布时间:2020-12-15 02:55:30 所属栏目:Java 来源:网络整理
导读:我试图通过使用 Java 8 Collection-Stream按多个属性对对象列表进行分组. 这非常有效: public class MyClass{ public String title; public String type; public String module; public MyClass(String title,String type,String module) { this.type = typ
我试图通过使用 Java 8 Collection-Stream按多个属性对对象列表进行分组.

这非常有效:

public class MyClass
{
   public String title;
   public String type;
   public String module;
   public MyClass(String title,String type,String module)
   {
      this.type = type;
      this.title = title;
      this.module= module;
   }
}

List<MyClass> data = new ArrayList();
data.add(new MyClass("1","A","B"));
data.add(new MyClass("2","B"));
data.add(new MyClass("3","C"));
data.add(new MyClass("4","B","A"));

Object result = data.stream().collect(Collectors.groupingBy((MyClass m) 
-> m.type,Collectors.groupingBy((MyClass m) -> m.module)));

但我想让它更有活力.
我只想指定一个应该用于GroupBy的String-Array(或List).

就像是:

Object groupListBy(List data,String[] groupByFieldNames)
{
    //magic code
}

我想打电话给:

groupListBy(data,new String[]{"type","module"});

如何使groupBy-Method更具动态性,就像在我的例子中一样?

解决方法

使代码更具动态性的主要问题是,您事先并不知道要分组的元素数量.在这种情况下,最好按所有元素的列表进行分组.这是有效的,因为如果两个列表的所有元素相同并且顺序相同,则它们是相等的.

在这种情况下,我们将按照由每种数据类型和模块组成的列表进行分组,而不是按类型和模块进行分组.

private static Map<List<String>,List<MyClass>> groupListBy(List<MyClass> data,String[] groupByFieldNames) {
    final MethodHandles.Lookup lookup = MethodHandles.lookup();
    List<MethodHandle> handles = 
        Arrays.stream(groupByFieldNames)
              .map(field -> {
                  try {
                      return lookup.findGetter(MyClass.class,field,String.class);
                  } catch (Exception e) {
                      throw new RuntimeException(e);
                  }
              }).collect(toList());
    return data.stream().collect(groupingBy(
            d -> handles.stream()
                        .map(handle -> {
                            try {
                                return (String) handle.invokeExact(d);
                            } catch (Throwable e) {
                                throw new RuntimeException(e);
                            }
                        }).collect(toList())
        ));
}

代码的第一部分将字段名称数组转换为MethodHandle的List.对于每个字段,为该字段检索MethodHandle:这是通过从MethodHandles.lookup()获取查找并查找给定字段名称的句柄来完成的. findGetter

Produces a method handle giving read access to a non-static field.

其余代码创建分类器来分组.在数据实例上调用所有句柄以返回String值列表.此流被收集到List中以用作分类器.

示例代码:

public static void main(String[] args) {
    List<MyClass> data = new ArrayList<>();
    data.add(new MyClass("1","B"));
    data.add(new MyClass("2","B"));
    data.add(new MyClass("3","C"));
    data.add(new MyClass("4","A"));

    System.out.println(groupListBy(data,new String[] { "type","module" }));
}

输出:

{[B,A]=[4],[A,B]=[1,2],C]=[3]}

当MyClass.toString()被覆盖以仅返回标题时.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读