【问题标题】:How can I shift an array of objects while wrapping without iteration?如何在不迭代的情况下移动对象数组?
【发布时间】:2013-10-30 22:24:14
【问题描述】:

如果A、B、C都是内存中的类,数组是元素0-2:

[0] = A
[1] = B
[2] = C

我想改变数组,让它变成这样:

[0] = C
[1] = A
[2] = B

我希望能够去任一方向,但我假设如果有人能指出我如何在一个方向上做这件事,我可以弄清楚另一个方向。

我想我应该提一下,如果可能的话,我需要这个而不需要迭代。

这是一个伪无限地形的 3D 游戏。数组中的每个对象都是地形数据块。我想改变它们,因为它们包含非常大的锯齿状数组,每个数组都有大量数据。当玩家移动时,我有地形滑动(进/出)内存。我从来没有考虑过只做一个 array.copy 来移动数组然后完全重建下一系列块的性能损失。

因此,为了消除这个相对较小的性能问题,我想用所描述的包装来移动数组,而不是通过重新分配内存来重建整个下一系列块,我将重新使用巨大的锯齿状数组通过将默认值复制到其中而不是完全重新初始化它们来提及。

为了让你看看我之前在做什么:

public void ShiftChunks(strVector2 ChunkOffset) {
            while (ChunkOffset.X < 0) {
                Array.Copy(Chunks, 0, Chunks, 1, Chunks.Length - 1);

                for (int X = 1; X < maxChunkArraySize; X++)
                    for (int Z = 0; Z < maxChunkArraySize; Z++) 
                        Chunks[X][Z].SetArrayPosition(X, Z);

                Chunks[0] = new clsChunk[maxChunkArraySize];

                for (int Z = 0; Z < maxChunkArraySize; Z++) 
                    Chunks[0][Z] = new clsChunk(0, Z);

                ChunkOffset.X++;
            }

            while (ChunkOffset.X > 0) {
                Array.Copy(Chunks, 1, Chunks, 0, Chunks.Length - 1);

                for (int X = 0; X < maxChunkArraySize - 1; X++)
                    for (int Z = 0; Z < maxChunkArraySize; Z++) 
                        Chunks[X][Z].SetArrayPosition(X, Z);

                Chunks[maxChunkArraySize - 1] = new clsChunk[maxChunkArraySize];

                for (int Z = 0; Z < maxChunkArraySize; Z++) 
                    Chunks[maxChunkArraySize - 1][Z] = new clsChunk(maxChunkArraySize - 1, Z);

                ChunkOffset.X--;
            }

            while (ChunkOffset.Z < 0) {
                for (int X = 0; X < maxChunkArraySize; X++) {
                    Array.Copy(Chunks[X], 0, Chunks[X], 1, Chunks[X].Length - 1);
                    for (int Z = 1; Z < maxChunkArraySize; Z++) 
                        Chunks[X][Z].SetArrayPosition(X, Z);

                    Chunks[X][0] = new clsChunk(X, 0);
                }
                ChunkOffset.Z++;
            }

            while (ChunkOffset.Z > 0) {
                for (int X = 0; X < maxChunkArraySize; X++) {
                    Array.Copy(Chunks[X], 1, Chunks[X], 0, Chunks[X].Length - 1);

                    for (int k = 0; k < maxChunkArraySize - 1; k++) 
                        Chunks[X][k].SetArrayPosition(X, k);

                    Chunks[X][maxChunkArraySize - 1] = new clsChunk(X, maxChunkArraySize - 1);
                }
                ChunkOffset.Z--;
            }
        }

如果有人想就我如何做得更好或如何进一步优化代码发表意见,请随时告诉我。

【问题讨论】:

  • 为什么禁止迭代?
  • 如何在不迭代的情况下移动数组中的每个元素?当然,它可以一次性完成,但你不能简单地告诉运行时“嘿,让这个数组从 那个 内存位置开始,然后让它返回那个位置。”数组不能像链表那样容易地重新排列;)。
  • @p.s.w.g 性能是我反对迭代的理由。
  • @MikeStrobel 标记您并回复,希望您能看到 Matthias 的答案。当您回复时,我最初可能没有很好地描述我的问题,或者您可能解释错误。

标签: c# jagged-arrays


【解决方案1】:
static void Rotate<T>(T[] source)
{
  var temp = source[source.Length - 1];
  Array.Copy(source, 0, source, 1, source.Length - 1);
  source[0] = temp;
}

【讨论】:

  • 如果你可以旋转指定数量的元素会更优雅;)。
  • 我保证这不是家庭作业。现在我回家了,我将编辑问题以详细说明我在做什么,并希望也能安抚 BartoszKP。
  • 对不起@TimWinter,那条评论是给 Mike Strobel 的 ;)
  • 很好,但本质上它并没有避免迭代:) 正如@MikeStrobel 在问题下的评论中指出的那样,迭代本质上嵌入在问题陈述本身中。
【解决方案2】:

我恰好在几天前为此创建了确切的东西:

private static T[] WrapAround<T>(T[] arr, int amount) {
        var newArr = new T[arr.Length];

        while (amount > 1) {
            for (var i = 0; i < arr.Length; i++) {
                if (i != 0) {
                    newArr[i] = arr[i - 1];
                }

                if (i == 0) {
                    newArr[i] = arr[arr.Length - 1];
                }
            }

            arr = (T[]) newArr.Clone();
            amount--;
        }

        return newArr;
    }

编辑:实际上,@Matthias 的解决方案要容易得多。您可能想改用它。

【讨论】:

  • 我仍然感谢您的回复。谢谢! :)
【解决方案3】:

这是一个仅使用Array.Copy() 将数组旋转任意方向(最多为数组的+/- 长度)的函数。

这是对上述 Matthias 回答的扩展。它分配一个具有偏移大小的临时数组来处理包装。

void Rotate<T>(T[] array, int offset) {
  if (offset==0) return;
  if (offset>0) {
    var temp = new T[offset];
    System.Array.Copy(array, array.Length-offset, temp, 0, offset);
    System.Array.Copy(array, 0, array, offset, array.Length-offset);
    System.Array.Copy(temp, 0, array, 0, offset);
  }else{
    var temp = new T[-offset];
    System.Array.Copy(array, 0, temp, 0, -offset);
    System.Array.Copy(array, -offset, array, 0, array.Length+offset);
    System.Array.Copy(temp, 0, array, array.Length+offset, -offset);
  }
}

但是,对于您描述的用例,根本不移动数组可能会更快,而是在检索数据时使用循环索引。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-08-04
    • 2015-04-19
    • 2019-01-19
    • 1970-01-01
    • 1970-01-01
    • 2019-02-21
    • 2020-10-14
    相关资源
    最近更新 更多