Java8将来自流的随机点与来自其他流的播放器对象相关联
这真的让我感到困惑。假设我有一个Java8将来自流的随机点与来自其他流的播放器对象相关联,java,java-8,java-stream,Java,Java 8,Java Stream,这真的让我感到困惑。假设我有一个Player对象,其中点p包含x和y值: class Player { void movePlayer(Point p) { ... } } public LongStream allValuesAsLong() { return LongStream.concat(LongStream.concat( LongStream.range(2384, 2413).map(x -> x <&l
Player
对象,其中点p
包含x
和y
值:
class Player {
void movePlayer(Point p) {
...
}
}
public LongStream allValuesAsLong() {
return LongStream.concat(LongStream.concat(
LongStream.range(2384, 2413).map(x -> x <<32 | 3072),
LongStream.range(3072, 3084).map(y -> 2413L <<32 | y)
),
//...
LongStream.range(2386, 2415).map(x -> x <<32 | 3135)
);
}
public List<Point> getRandomPoints(int num) {
long count=allValuesAsLong().count();
assert count > num;
return new Random().longs(0, count)
.distinct()
.limit(num)
.mapToObj(i -> allValuesAsLong().skip(i)
.mapToObj(l -> new Point((int)(l>>>32), (int)(l&(1L<<32)-1)))
.findFirst().get())
.collect(Collectors.toList());
}
如果我有一堆静态点(当然比玩家多),我需要随机但唯一地映射到每个玩家的movePlayer函数,我会怎么做?这个过程不需要很快完成,但每次都要经常随机完成。为了增加一层复杂性,我的点是由变化的x和y值生成的。到目前为止,我正在执行以下操作(导致JVM崩溃):
现在,当我使用一些荒谬的抽象流
,除了它只使用第一个流
中的点之外,这几乎奏效了
我是不是完全忽略了溪流的意义?我只是喜欢不创建明确的
点
对象的想法,我无论如何都不会使用这些对象。您应该这样做:
final int PLAYERS_COUNT = 6;
List<Point> points = generatePointStream()
.stream()
.limit(PLAYERS_COUNT)
.map(s -> s.findAny().get())
.collect(Collectors.toList());
你应该这样做:
final int PLAYERS_COUNT = 6;
List<Point> points = generatePointStream()
.stream()
.limit(PLAYERS_COUNT)
.map(s -> s.findAny().get())
.collect(Collectors.toList());
您可以定义一个返回
点流的方法,如
public Stream<Point> allValues() {
return Stream.of(
IntStream.range(2384, 2413).mapToObj(x -> new Point(x, 3072)),
IntStream.range(3072, 3084).mapToObj(y -> new Point(2413, y)),
//...
IntStream.range(2386, 2415).mapToObj(x -> new Point(x, 3135))
).flatMap(Function.identity());
}
有一个关于创建太深的连接流的警告,但是如果您像这里一样控制创建,您可以创建一个平衡的树,如
Stream.concat(
Stream.concat(
Stream.concat(a, b),
Stream.concat(c, d)
),
Stream.concat(
Stream.concat(a, b),
Stream.concat(c, d)
)
)
然而,即使这样的流允许在不处理元素的情况下计算大小,这在Java9之前是不会发生的。在Java 8中,count()
将始终迭代所有元素,这意味着在count()
操作之后,已经实例化了与将所有元素收集到列表中时一样多的点
实例
更糟糕的是,skip
不会传播到流的源,因此当说Stream.map(…).skip(n).findFirst()
时,映射函数的计算次数最多为n+1次,而不是仅计算一次。当然,这使得getRandomPoints
方法的整个思想都变得毫无用处。由于这里的封装和嵌套流,我们甚至不能在映射之前移动跳过
操作
请注意,临时实例的处理可能仍然比收集到一个列表中更有效,因为列表中的所有实例都同时存在,但很难预测,因为这里的数量要大得多。因此,如果实例创建确实是一个问题,我们可以解决这个特定情况,因为组成一个点的两个int
值可以封装在一个基本long
值中:
class Player {
void movePlayer(Point p) {
...
}
}
public LongStream allValuesAsLong() {
return LongStream.concat(LongStream.concat(
LongStream.range(2384, 2413).map(x -> x <<32 | 3072),
LongStream.range(3072, 3084).map(y -> 2413L <<32 | y)
),
//...
LongStream.range(2386, 2415).map(x -> x <<32 | 3135)
);
}
public List<Point> getRandomPoints(int num) {
long count=allValuesAsLong().count();
assert count > num;
return new Random().longs(0, count)
.distinct()
.limit(num)
.mapToObj(i -> allValuesAsLong().skip(i)
.mapToObj(l -> new Point((int)(l>>>32), (int)(l&(1L<<32)-1)))
.findFirst().get())
.collect(Collectors.toList());
}
public LongStream allValuesAsLong(){
返回LongStream.concat(LongStream.concat(
LongStream.range(23842413).map(x->x>>32),(int)(l&(1L好的,您可以定义一个方法,返回点流
public Stream<Point> allValues() {
return Stream.of(
IntStream.range(2384, 2413).mapToObj(x -> new Point(x, 3072)),
IntStream.range(3072, 3084).mapToObj(y -> new Point(2413, y)),
//...
IntStream.range(2386, 2415).mapToObj(x -> new Point(x, 3135))
).flatMap(Function.identity());
}
有一个关于创建太深的连接流的警告,但是如果您像这里一样控制创建,您可以创建一个平衡的树,如
Stream.concat(
Stream.concat(
Stream.concat(a, b),
Stream.concat(c, d)
),
Stream.concat(
Stream.concat(a, b),
Stream.concat(c, d)
)
)
然而,即使这样的流允许在不处理元素的情况下计算大小,这在Java9之前是不会发生的
将始终迭代所有元素,这意味着在执行count()
操作后,已经实例化了与将所有元素收集到列表中时一样多的点
实例
更糟糕的是,skip
不会传播到流的源,因此在说Stream.map(…).skip(n).findFirst()时
,映射函数的计算次数最多为n+1
次,而不是仅计算一次。当然,这使得getRandomPoints
方法的整个思想都变得毫无用处。由于这里的封装和嵌套流,我们甚至无法在ma之前移动skip
操作p
请注意,临时实例的处理可能比收集到一个列表中更有效,其中的所有实例都同时存在,但由于我们这里的数量要大得多,因此很难预测。因此,如果实例创建确实是一个问题,我们可以解决此特定情况,因为两个int
v构成点的值可以封装在基本long
值中:
class Player {
void movePlayer(Point p) {
...
}
}
public LongStream allValuesAsLong() {
return LongStream.concat(LongStream.concat(
LongStream.range(2384, 2413).map(x -> x <<32 | 3072),
LongStream.range(3072, 3084).map(y -> 2413L <<32 | y)
),
//...
LongStream.range(2386, 2415).map(x -> x <<32 | 3135)
);
}
public List<Point> getRandomPoints(int num) {
long count=allValuesAsLong().count();
assert count > num;
return new Random().longs(0, count)
.distinct()
.limit(num)
.mapToObj(i -> allValuesAsLong().skip(i)
.mapToObj(l -> new Point((int)(l>>>32), (int)(l&(1L<<32)-1)))
.findFirst().get())
.collect(Collectors.toList());
}
public LongStream allValuesAsLong(){
返回LongStream.concat(LongStream.concat(
LongStream.range(23842413.map(x->x>>32),(int)(l)&(1)很棒的东西!你建议如何建立一个由所有这些随机点组成的流?或者你是否使用了我拥有的?这完全取决于你需要什么,因为你的情况非常具体。你有6个点,必须在它们的特定范围内生成,然后重新排列。一般的随机点流很容易通过extendi实现ngAbstractSpliterator
。如果我有一个可变数量的玩家怎么办?我需要这个限制吗,因为不计算玩家列表的大小会很好(我的应用程序需要一个循环)。老实说,我根本不明白OP为什么创建一个列表
,所以你决定只做findAny()
在这些流上,它将简单地返回这个特定用例中的第一个元素,这样做是正确的。但是,当只考虑这些流的第一个元素时,生成n
点流仍然没有意义,换句话说,只在第一个位置生成n
点将产生e完全相同的结果,使整个嵌套流操作过时。唯一的问题是,我的点没有遵循一个简单的趋势(我看到),可以使用一个流创建。为了解决这个问题,我尝试做了一个flatMap
类似的:stream()…flatMap(t->t)..
。这使得一个包含所有点的大流而不是一个流的流。您的评论使我认为最好的解决方案可能是定制点