使用Java8收集器收集索引

时间:2017-07-19 22:51:08

标签: scala java-8 collectors

我有一个形状流

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

其中Shape

public enum Shape {TRIANGLE, CIRCLE, SQUARE}

如何编写将形状流分组为a的函数 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,但我无法绕过它。

2 个答案:

答案 0 :(得分: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));

答案 1 :(得分: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));