dea*_*mon 26 java scala java-stream
我尝试使用Streams API将以下Scala行转换为Java 8:
// Scala
util.Random.shuffle((1 to 24).toList)
Run Code Online (Sandbox Code Playgroud)
要在Java中编写等效项,我创建了一系列整数:
IntStream.range(1, 25)
Run Code Online (Sandbox Code Playgroud)
我怀疑toList在流API中找到了一个方法,但IntStream只知道奇怪的方法:
collect(
Supplier<R> supplier, ObjIntConsumer<R> accumulator, BiConsumer<R,R> combiner)
Run Code Online (Sandbox Code Playgroud)
如何使用Java 8 Streams API对列表进行混洗?
And*_*hev 32
干得好:
List<Integer> integers =
IntStream.range(1, 10) // <-- creates a stream of ints
.boxed() // <-- converts them to Integers
.collect(Collectors.toList()); // <-- collects the values to a list
Collections.shuffle(integers);
System.out.println(integers);
Run Code Online (Sandbox Code Playgroud)
打印:
[8, 1, 5, 3, 4, 2, 6, 9, 7]
Run Code Online (Sandbox Code Playgroud)
Pau*_*ton 24
您可能会发现以下toShuffledList()方法很有用.
private static final Collector<?, ?, ?> SHUFFLER = Collectors.collectingAndThen(
Collectors.toCollection(ArrayList::new),
list -> {
Collections.shuffle(list);
return list;
}
);
@SuppressWarnings("unchecked")
public static <T> Collector<T, ?, List<T>> toShuffledList() {
return (Collector<T, ?, List<T>>) SHUFFLER;
}
Run Code Online (Sandbox Code Playgroud)
这样可以实现以下类型的单线程:
IntStream.rangeClosed('A', 'Z')
.mapToObj(a -> (char) a)
.collect(toShuffledList())
.forEach(System.out::print);
Run Code Online (Sandbox Code Playgroud)
示例输出:
AVBFYXIMUDENOTHCRJKWGQZSPL
Run Code Online (Sandbox Code Playgroud)
您可以使用自定义比较器按随机值"排序"值:
public final class RandomComparator<T> implements Comparator<T> {
private final Map<T, Integer> map = new IdentityHashMap<>();
private final Random random;
public RandomComparator() {
this(new Random());
}
public RandomComparator(Random random) {
this.random = random;
}
@Override
public int compare(T t1, T t2) {
return Integer.compare(valueFor(t1), valueFor(t2));
}
private int valueFor(T t) {
synchronized (map) {
return map.computeIfAbsent(t, ignore -> random.nextInt());
}
}
}
Run Code Online (Sandbox Code Playgroud)
流中的每个对象(懒惰地)关联一个随机整数值,我们对其进行排序.地图上的同步是处理并行流.
然后你就可以这样使用它:
IntStream.rangeClosed(0, 24).boxed()
.sorted(new RandomComparator<>())
.collect(Collectors.toList());
Run Code Online (Sandbox Code Playgroud)
该解决方案的优点是它集成在流管道中.
如果您想处理整个流而没有太多麻烦,您可以简单地使用以下方法创建自己的收集器Collectors.collectingAndThen():
public static <T> Collector<T, ?, Stream<T>> toEagerShuffledStream() {
return Collectors.collectingAndThen(
toList(),
list -> {
Collections.shuffle(list);
return list.stream();
});
}
Run Code Online (Sandbox Code Playgroud)
limit()但如果您想要生成的流,则这不会很好地执行。为了克服这个问题,可以创建一个自定义 Spliterator:
package com.pivovarit.stream;
import java.util.List;
import java.util.Objects;
import java.util.Random;
import java.util.RandomAccess;
import java.util.Spliterator;
import java.util.function.Consumer;
import java.util.function.Supplier;
class ImprovedRandomSpliterator<T, LIST extends RandomAccess & List<T>> implements Spliterator<T> {
private final Random random;
private final List<T> source;
private int size;
ImprovedRandomSpliterator(LIST source, Supplier<? extends Random> random) {
Objects.requireNonNull(source, "source can't be null");
Objects.requireNonNull(random, "random can't be null");
this.source = source;
this.random = random.get();
this.size = this.source.size();
}
@Override
public boolean tryAdvance(Consumer<? super T> action) {
if (size > 0) {
int nextIdx = random.nextInt(size);
int lastIdx = --size;
T last = source.get(lastIdx);
T elem = source.set(nextIdx, last);
action.accept(elem);
return true;
} else {
return false;
}
}
@Override
public Spliterator<T> trySplit() {
return null;
}
@Override
public long estimateSize() {
return source.size();
}
@Override
public int characteristics() {
return SIZED;
}
}
Run Code Online (Sandbox Code Playgroud)
进而:
public final class RandomCollectors {
private RandomCollectors() {
}
public static <T> Collector<T, ?, Stream<T>> toImprovedLazyShuffledStream() {
return Collectors.collectingAndThen(
toCollection(ArrayList::new),
list -> !list.isEmpty()
? StreamSupport.stream(new ImprovedRandomSpliterator<>(list, Random::new), false)
: Stream.empty());
}
public static <T> Collector<T, ?, Stream<T>> toEagerShuffledStream() {
return Collectors.collectingAndThen(
toCollection(ArrayList::new),
list -> {
Collections.shuffle(list);
return list.stream();
});
}
}
Run Code Online (Sandbox Code Playgroud)
我在这里解释了性能注意事项:https ://4compressive.com/implementing-a-randomized-stream-spliterator-in-java/
| 归档时间: |
|
| 查看次数: |
21003 次 |
| 最近记录: |