3 个嵌套的 for-each 循环作为 Java Stream

问题描述 投票:0回答:1

在我目前正在进行的项目中,我们有三个嵌套 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

我做错了什么?

java stream nested-loops
1个回答
0
投票

我想用流来完成所有这一切,以使其更快

好的。我将把你的问题解释为“我怎样才能让它更快”。

对于初学者来说;使用 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 深循环,效率大大提高。这就是你如何让它变得更快。用一种代码结构替换另一种代码结构不会产生任何算法复杂性差异,而且实际上甚至不会给你带来恒定的(即大部分不相关的,但仍然)速度提升 - 如果有的话,它会减慢速度。

是的,那么我怎样才能让它更快呢?

  1. 计算范围内的奇异 x 值,使 newPos 的 x 分量为 0。这是一个简单的加法/减法,然后是范围检查。 不涉及任何循环

  2. 对 z 执行相同操作。

  3. 现在循环,仅针对

    y
    。一旦 y 超出范围(
    newPos.getY()
    为 0 或以上),就突破 - 无论如何它都不会回落到范围内。

使用基本循环(无 lambda),这样这些事情就简单多了。

© www.soinside.com 2019 - 2024. All rights reserved.