在我目前正在进行的项目中,我们有三个嵌套 for 循环的构造:
final Vector3i startPose = new Vector3i(-3, -2, -3);
final Vector3i finishPos = new Vector3i(3, 4, 3);
final Vector3i currentPos = entity.getPos();
final List<Vector3i> entityFinderZone = new ArrayList<>();
for (int x = startPos.getX(); x <= finishPos.getX(); x++)
{
for (int y = startPos.getY(); y <= finishPos.getY(); y++)
{
for (int z = startPos.getX(); z <= finishPos.getZ(); z++)
{
Vector3i newPos = currentPos.offset(x ,y ,z);
if (newPos.getX() == 0 && newPos.getZ() == 0 && (newPos.getY() < -1 || newPos.getZ() > 2))
{
entityFinderZone.add(newPos);
}
}
}
}
我想用流来完成所有这些操作以使其更快,但我收到错误
final IntStream xCoords = IntStream.iterate(startPos.getX(), i -> i <= finishPos.getX(), i -> i + 1);
final IntStream yCoords = IntStream.iterate(startPos.getY(), i -> i <= finishPos.getY(), i -> i + 1);
final IntStream zCoords = IntStream.iterate(startPos.getZ(), i -> i <= finishPos.getZ(), i -> i + 1);
entityFinderZone = xCoords.
flatMap( x -> yCoords.
flatMap(y -> zCoords.
flatMap(z -> currentPos.offset(x, y, z)))).collect(Collectors.toList());
错误:
Bad return type in lambda expression: Vector3i cannot be converted to int
我做错了什么?
我想用流来完成所有这一切,以使其更快
好的。我将把你的问题解释为“我怎样才能让它更快”。
对于初学者来说;使用 lambda 不是。这并不会让任何事情变得更快。最佳情况下,Lambda 可以让您更轻松地并行化任务,但这并不是免费的,而且几乎总是,如果任务对性能至关重要以至于必须并行化,那么您想要控制该过程,而不仅仅是很好地询问流尽力而为(这是你所能做的——没有保证,也没有关于如何做到这一点的特定结构)。
一般来说,“我会使用 lambda,因为它们更快”是一种不正确的心态。
一般来说,“我会使用 lambda,因为它们更好”是一种不正确的心态。
正确的心态是:“我可以用 lambda 来做到这一点。如果我能预见到代码从表面上看会更容易阅读并且更容易维护(即不是使用诸如“每个人都知道 lambda 更容易阅读”之类的循环推理,因此使用 lambda 将使这更容易阅读,QED') - 那么我将使用它们。如果没有,我不会“。
if (newPos.getX() == 0 && newPos.getZ() == 0 && (newPos.getY() < -1 || newPos.getZ() > 2))
如果这就是你想做的全部,那么三重循环会使效率变得极其低下。
如果此
if
未触发,则您的循环不会执行任何操作。仅看 if,我们有一些布尔属性:
对于
[startPos.x, finishPos.x]
范围内的 1 或 0 个数字,[startPos.x, finishPos.x]
的 x 偏移量(对于函数来说是常量)为 0。如果没有这样的数字,则此方法 什么也不做 并且是最快的方法我们“无能为力”就是尽快返回。否则,循环 startPos.x-finishPos.x
绝对没有意义 - 除了那个数字之外什么也不会发生。
完全相同的逻辑适用于
[startPos.z, finishPos.z]
范围。
对于
y
组件,newPos.getZ() > 2
不可能为真 - 毕竟,newPos.getZ() 必须是 0
,否则我们甚至不会到达这里。 &&
表示 AND:所有 3 个条件都必须成立。因此,归结为 newPos.getY() < -1
,这意味着存在 [startPos.y, endPos.y]
的子范围。我们确实必须循环 - 我们可以减少一些循环的大小。
这使得 3 深循环成为 1 深循环,效率大大提高。这就是你如何让它变得更快。用一种代码结构替换另一种代码结构不会产生任何算法复杂性差异,而且实际上甚至不会给你带来恒定的(即大部分不相关的,但仍然)速度提升 - 如果有的话,它会减慢速度。
计算范围内的奇异 x 值,使 newPos 的 x 分量为 0。这是一个简单的加法/减法,然后是范围检查。 不涉及任何循环。
对 z 执行相同操作。
现在循环,仅针对
y
。一旦 y 超出范围(newPos.getY()
为 0 或以上),就突破 - 无论如何它都不会回落到范围内。
使用基本循环(无 lambda),这样这些事情就简单多了。