使用Java 8 Streams API随机播放整数列表

时间:2013-11-18 21:31:30

标签: java scala java-stream

我尝试使用Streams API将以下Scala行转换为Java 8:

// Scala
util.Random.shuffle((1 to 24).toList)

要在Java中编写等效项,我创建了一系列整数:

IntStream.range(1, 25)

我怀疑在流API中找到toList方法,但IntStream只知道奇怪的方法:

collect(
  Supplier<R> supplier, ObjIntConsumer<R> accumulator, BiConsumer<R,R> combiner)

如何使用Java 8 Streams API对列表进行混洗?

9 个答案:

答案 0 :(得分:31)

你走了:

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);

打印:

[8, 1, 5, 3, 4, 2, 6, 9, 7]

答案 1 :(得分:23)

您可能会发现以下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;
}

这可以实现以下类型的单行:

IntStream.rangeClosed('A', 'Z')
         .mapToObj(a -> (char) a)
         .collect(toShuffledList())
         .forEach(System.out::print);

示例输出:

AVBFYXIMUDENOTHCRJKWGQZSPL

答案 2 :(得分:6)

您可以使用自定义比较器按随机值“排序”值:

IntStream.rangeClosed(0, 24).boxed()
    .sorted(new RandomComparator<>())
    .collect(Collectors.toList());

流中的每个对象(懒惰地)关联一个随机整数值,我们对其进行排序。地图上的同步是处理并行流。

然后你可以这样使用它:

data

此解决方案的优点是它集成在流管道中。

答案 3 :(得分:1)

要有效地执行随机播放,您需要提前获取所有值。将流转换为类似于Scala中的列表后,可以使用Collections.shuffle()。

答案 4 :(得分:0)

如果您正在寻找“仅流媒体”解决方案和确定性解决方案,仅仅“偶然”排序与“随机”排序是足够好的,您可以随时按哈希值对int s进行排序:

List<Integer> xs=IntStream.range(0, 10)
    .boxed()
    .sorted( (a, b) -> a.hashCode() - b.hashCode() )
    .collect(Collectors.toList());

如果您想要int[]而不是List<Integer>,则可以稍后将其取消装箱。不幸的是,你已经完成了拳击步骤以应用自定义Comparator,所以没有消除这部分过程。

List<Integer> ys=IntStream.range(0, 10)
    .boxed()
    .sorted( (a, b) -> a.hashCode() - b.hashCode() )
    .mapToInt( a -> a.intValue())
    .toArray();

答案 5 :(得分:0)

如果您希望处理整个Stream时没有太多麻烦,则可以使用Collectors.collectingAndThen()创建自己的收集器:

public static <T> Collector<T, ?, Stream<T>> toEagerShuffledStream() {
    return Collectors.collectingAndThen(
      toList(),
      list -> {
          Collections.shuffle(list);
          return list.stream();
      });
}

但是,如果您想limit()生成的流,这将不能很好地执行。为了克服这一点,可以创建一个自定义的Spliterator:

package com.pivovarit.stream;

import java.util.List;
import java.util.Random;
import java.util.Spliterator;
import java.util.function.Consumer;
import java.util.function.Supplier;

public class ImprovedRandomSpliterator<T> implements Spliterator<T> {

    private final Random random;
    private final T[] source;
    private int size;

    ImprovedRandomSpliterator(List<T> source, Supplier<? extends Random> random) {
        if (source.isEmpty()) {
            throw new IllegalArgumentException("RandomSpliterator can't be initialized with an empty collection");
        }
        this.source = (T[]) source.toArray();
        this.random = random.get();
        this.size = this.source.length;
    }

    @Override
    public boolean tryAdvance(Consumer<? super T> action) {
        int nextIdx = random.nextInt(size);
        int lastIdx = size - 1;

        action.accept(source[nextIdx]);
        source[nextIdx] = source[lastIdx];
        source[lastIdx] = null; // let object be GCed
        return --size > 0;
    }

    @Override
    public Spliterator<T> trySplit() {
        return null;
    }

    @Override
    public long estimateSize() {
        return source.length;
    }

    @Override
    public int characteristics() {
        return SIZED;
    }
}

然后:

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();
          });
    }
}

我在这里解释了性能注意事项:https://4comprehension.com/implementing-a-randomized-stream-spliterator-in-java/

答案 6 :(得分:0)

public static List<Integer> getSortedInRandomOrder(List<Integer> list) {
    return list
            .stream()
            .sorted((o1, o2) -> ThreadLocalRandom.current().nextInt(-1, 2))
            .collect(Collectors.toList());
}

答案 7 :(得分:0)

List<Integer> randomShuffledRange(int startInclusive, int endExclusive) {
    return new Random().ints(startInclusive, endExclusive)
            .distinct()
            .limit(endExclusive-startInclusive)
            .boxed()
            .collect(Collectors.toList());
}

var shuffled = randomShuffledRange(1, 10);
System.out.println(shuffled);

示例输出:

[4, 6, 8, 9, 1, 7, 3, 5, 2]

答案 8 :(得分:-2)

这是我的一线解决方案: 我正在挑选一种颜色:

colourRepository.findAll().stream().sorted((o1,o2)-> RandomUtils.nextInt(-1,1)).findFirst().get()