Вопрос

If A, B, and C are all classes in memory and the array is elements 0-2:

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

I want to shift the array so that it turns into this:

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

I would want to be able to go either direction, but I'd assume if someone could point me towards how to do it in one direction I can figure out the other.

Thought I should mention, I need this without iteration if at all possible.

This is for a 3D game of pseudo-infinite terrain. Each object in the arrays are chunks of terrain data. I want to shift them as they contain extremely large jagged arrays with a significant amount of data each. As the player moves, I have terrain sliding (in to/out of) memory. I never considered the performance hit of doing only an array.copy to shift arrays followed by completely rebuilding the next series of chunks.

So to eliminate this relatively minor performance issue, I wanted to shift the arrays with wrapping as described and instead of rebuilding the whole next series of chunks by re-allocating memory, I'm going to re-use the huge jagged arrays mentioned by copying default values into them rather than completely reinitializing them.

For kicks so you can see what I was doing before:

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

If anyone would like to give opinions on how I might do this even better or how to optimize the code further, feel free to let me know.

Это было полезно?

Решение

static void Rotate<T>(T[] source)
{
  var temp = source[source.Length - 1];
  Array.Copy(source, 0, source, 1, source.Length - 1);
  source[0] = temp;
}

Другие советы

I happen to have created the exact thing for this just a few days ago:

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

Edit: Actually, @Matthias' solution is a lot easier.. You might want to use that instead.

Here's a function that will rotate an array by any offset in either direction (up to +/- length of the array) using just Array.Copy().

This is an extension of Matthias's answer above. It allocates a temporary array with the size of the offset to deal with wrapping.

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

However, for the use case you described, it might be faster to not shift the array at all, but rather use a cyclical index when retrieving your data.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top