在Java 8中以惯用方式枚举对象流

err*_*ist 4 java enumeration java-8 java-stream

如何使用Java 8流方法(例如,对于数组,创建一个求值的地方),以惯用方式枚举Stream<T>哪个T实例将每个实例映射到一个唯一的整数?T[] valuesMap<T,Integer>Map.get(values[i]) == itrue

目前,我正在定义一个匿名类,它增加一个int字段以便与该Collectors.toMap(..)方法一起使用:

private static <T> Map<T, Integer> createIdMap(final Stream<T> values) {
    return values.collect(Collectors.toMap(Function.identity(), new Function<T, Integer>() {

        private int nextId = 0;

        @Override
        public Integer apply(final T t) {
            return nextId++;
        }

    }));
}
Run Code Online (Sandbox Code Playgroud)

但是,使用Java 8流API是否没有更简洁/更优雅的方式? - 如果可以安全地并行化,则可获得奖励积分.

Hol*_*ger 5

如果存在重复元素,您的方法将失败.

除此之外,您的任务需要可变状态,因此可以通过Mutable减少来解决.当我们填充地图时,我们可以简单地使用地图的大小来获取未使用的ID.

更棘手的部分是合并操作.以下操作只是重复右图的分配,这将处理潜在的重复.

private static <T> Map<T, Integer> createIdMap(Stream<T> values) {
    return values.collect(HashMap::new, (m,t) -> m.putIfAbsent(t,m.size()),
        (m1,m2) -> {
            if(m1.isEmpty()) m1.putAll(m2);
            else m2.keySet().forEach(t -> m1.putIfAbsent(t, m1.size()));
        });
}
Run Code Online (Sandbox Code Playgroud)

如果我们依赖于唯一元素,或者插入一个显式distinct(),我们可以使用

private static <T> Map<T, Integer> createIdMap(Stream<T> values) {
    return values.distinct().collect(HashMap::new, (m,t) -> m.put(t,m.size()),
        (m1,m2) -> { int leftSize=m1.size();
            if(leftSize==0) m1.putAll(m2);
            else m2.forEach((t,id) -> m1.put(t, leftSize+id));
        });

}
Run Code Online (Sandbox Code Playgroud)