使用Java 8流为对象分配唯一的ID

5
static <T> Map<T, Integer> assignIds(Collection<T> objects);

我希望编写一个函数,它接收一组唯一的对象,并为每个对象分配一个不同的ID号码。这些ID号码应按顺序分配。
我可以使用显式循环轻松完成此操作,例如:
Map<T, Integer> ids = new HashMap<>();
int id = 0;

for (T object: objects) {
    ids.put(object, id++);
}

有没有一种优雅的方法可以使用新的Java 8 Stream API来完成这个任务?

2个回答

6
这里有一种方法:
static <T> Map<T, Integer> assignIds(Collection<T> objects) {
    AtomicInteger ai = new AtomicInteger();
    return objects.stream()
                  .collect(Collectors.toMap(o -> o, o -> ai.getAndIncrement()));
}

上述解决方案也可以使用parallelStream()代替stream()
这是另一种依次运行的解决方案:
static <T> Map<T, Integer> assignIds(Collection<T> objects) {
    Map<T, Integer> result = new HashMap<>();
    objects.stream().forEachOrdered(o -> result.put(o, result.size()));        
    return result;
}

在ZouZou的回答基础上进行改进...
static <T> Map<T, Integer> assignIds(Collection<T> objects) {
    OfInt ids = IntStream.range(0, objects.size()).iterator();
    return objects.stream().collect(Collectors.toMap(o -> o, o -> ids.next()));
}

例如,在Scala中完成这个操作的惯用方式是使用zipWithIndex方法。但是,在Java 8 Streams API中没有这种方法,甚至没有zip方法,也无法与IntStream结合使用。


6
您可以使用原始迭代器来生成id:
static <T> Map<T, Integer> assignIds(Collection<T> objects) {
    PrimitiveIterator.OfInt iterator = IntStream.iterate(0, x -> x + 1)
                .limit(objects.size())
                .iterator();
    return objects.stream().collect(Collectors.toMap(obj -> obj, id -> iterator.next()));
}

你可能会想使用protonpack库,它为Streams定义了一些实用方法(例如zipWithIndex)。因此,代码可能如下所示:

static <T> Map<T, Long> assignIds(Collection<T> objects) {
    return StreamUtils.zipWithIndex(objects.stream())
                .collect(Collectors.toMap(Indexed::getValue, Indexed::getIndex));
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接