2015-12-08 44 views
2

我是java Stream API的新手,并且有解决使用它的用例。在java中分组8 8 Stream API

Map<Object, ? extends Object> map = list.stream().collect(Collectors.groupingBy(p->p.getX() 
                  ,Collectors.groupingBy(p->p.getY() 
                  ,Collectors.groupingBy(p->p.getZ())))); 

考虑到x,y和z是给定类的属性。如果我们具有预定义的分组顺序(哪个属性需要考虑第一个,第二个等...),这可以正常工作。

(给定的一段代码属性x被认为是1st,y 2nd和z 3rd)。

现在,就我而言,分组的顺序不是预定义的,可能会在运行时更改。所以,在编译时,我不知道在collect方法中传递什么。 我正在寻找一种解决方案,通过该解决方案,我可以读取配置字符串并在运行时更改分组。

+0

你是什么意思“读取配置串并改变在分组运行。”? – Tunaki

+0

好的,让我们假设它是用户定义的 - 所以如果用户定义了groupingOrder = x,y,z它应该如上所述分组,如果另一个用户将其定义为y,x,z,它应该相应地改变..(* groupingOrder只是我的名字作为参考) – Sachin

回答

1

您可以创建使用给定的分类功能,它建立自己Collector一个辅助方法:

@SuppressWarnings("unchecked") 
@SafeVarargs 
public static <T> Collector<T, ?, Map<?, ?>> multiGrouping(
               Function<? super T, ?>... classifiers) { 
    Collector<T, ?, Map<?, ?>> result = null; 
    for(int i=classifiers.length-1; i>=0; i--) { 
     Collector<?, ?, ?> next; 
     if(result == null) { 
      next = Collectors.groupingBy(classifiers[i]); 
     } else { 
      next = Collectors.groupingBy(classifiers[i], result); 
     } 
     result = (Collector<T, ?, Map<?, ?>>)next; 
    } 
    return result; 
} 

用例:

Map<?, ?> map = Stream.of("abc", "def", "cd", "cfff") 
         .collect(multiGrouping(String::length, s -> s.charAt(0))); 
+0

谢谢,明白了..我正在寻找相同的.. – Sachin

1

假设pP类的,你可以定义的顺序是这样的:

Function<P, Object> g1 = P::getX; 
Function<P, Object> g2 = P::getX; 
Function<P, Object> g3 = P::getX; 

然后:

list.stream().collect(Collectors.groupingBy(g1, 
         Collectors.groupingBy(g2, 
          Collectors.groupingBy(g3)))); 

的G1,G2,G3也可以使用反射来访问定义基于字段/方法名称的运行时方法/字段。

+0

感谢您的快速回复,在这种情况下,我是否需要定义所有属性的顺序?我想在运行时基于配置字符串构造“Collectors.groupingBy(...”作为字符串(如**“list.stream()。collect(Collectors.groupingBy(g1,Collectors.groupingBy(g2, Collectors.groupingBy(g3))));“**然后使用groovy执行它,但它似乎像当前的常规版本不支持lambda .. – Sachin