2017-07-19 61 views
1

我有形状收集指数

Stream<Shape> shapes = Arrays.asList(TRIANGLE, CIRCLE, SQUARE, SQUARE, CIRCLE, TRIANGLE, TRIANGLE).stream(); 

的流,其中Shape

public enum Shape {TRIANGLE, CIRCLE, SQUARE} 

我怎样可以编写组形状流转换成 Map<Shape, List<Integer>>使得指数是一个功能根据形状收集?

public Map<Shape, List<Integer>> indexedPartition(Stream<Shape> shapes) { 
//code here 
} 

在功能indexedPartition的电流输出示例如下所示

TRIANGE -> {0, 5, 6} 
CIRCLE -> {1, 4} 
SQUARE -> {2, 3} 

在Scala中我会做类似

val indices = Stream.from(0) 

object Shape extends Enumeration { 
    type Shape = Value 
    val CIRCLE, TRIANGLE, SQUARE = Value 
} 

val shapes = Stream(Shape.TRIANGLE, Shape.CIRCLE, Shape.SQUARE, Shape.SQUARE, Shape.CIRCLE, Shape.TRIANGLE, Shape.TRIANGLE) 

(shapes zip indices).groupBy{ case (s, i) => s }.mapValues(l => l.map(_._2)) 
//res0: scala.collection.immutable.Map[Shape.Value,List[Int]] = Map(SQUARE -> List(2, 3), TRIANGLE -> List(0, 5, 6), CIRCLE -> List(1, 4)) 

我在Java中使用Collectors.groupingBy尝试,但我可以我的头围绕着它。

回答

3

流过的索引:

import static java.util.stream.Collectors.groupingBy; 


List<Shape> shapes = Arrays.asList(TRIANGLE, CIRCLE, SQUARE, SQUARE, CIRCLE, TRIANGLE, TRIANGLE); 

result = IntStream.range(0, shapes.size()) 
     .boxed() 
     .collect(groupingBy(shapes::get)); 
+0

你可以请编辑您的'流 shapes'答案吗? –

+0

@ApoorvIngle你不能做'流' - 因为它没有索引 – Eugene

+0

@Eugene如何使用'Streams.zip'或类似的构造来创建一个元组,然后按照我已经演示的那样收集它我的Scala片段。或者我的Java Collectors.collect概念是完全错误的? –

1

,能够实现作为Collector在流处理结束遇到它记录一个元素的索引。当然,这个数对于无序流是没有意义的,如果你有大小改变的中间运算,如filterflatMap,那么这个数字将不再反映原始数组中的位置。

class IndexCollector<K> { 
    int total; 
    Map<K,List<Integer>> map = new HashMap<>(); 

    public static <T> Collector<T,?,Map<T,List<Integer>>> get() { 
     return Collector.of(IndexCollector<T>::new, 
      (c,t) -> c.map.computeIfAbsent(t, x -> new ArrayList<>()).add(c.total++), 
      (c1,c2) -> merge(c1, c2), 
      c -> c.map); 
    } 
    static <T> IndexCollector<T> merge(IndexCollector<T> a, IndexCollector<T> b) { 
     if(a.total == 0) return b; 
     if(b.total != 0) { 
      int offset = a.total; 
      b.map.forEach((t,l) -> { 
       List<Integer> target = a.map.computeIfAbsent(t, x -> new ArrayList<>()); 
       for(Integer i: l) target.add(i+offset); 
      }); 
      a.total += b.total; 
     } 
     return a; 
    } 
} 

可以使用像

Map<Shape, List<Integer>> map = 
    Stream.of(TRIANGLE, CIRCLE, SQUARE, SQUARE, CIRCLE, TRIANGLE, TRIANGLE) 
      .collect(IndexCollector.get()); 

map.forEach((shape,list) -> System.out.printf("%-9s%s%n", shape, list)); 
+0

我也考虑过这个问题......依靠元素以相遇顺序到达收藏家*的事实,但出于您陈述的原因,我放弃了这个想法。仍然+1。 – Eugene

+0

谢谢你的回答@霍尔。 难道你不认为这是相当冗长/繁琐的实现,特别是当我们不能保证在我们过滤/ flatMap时保留索引。是否有一种方法可以提供一个外部索引生成器,与流中的每个形状元素绑定,就像在Scala中一样? –

+0

不符合可接受的性能。 – Holger