如何在C#中移动数组的开头?

Mik*_*ike 5 c# arrays

我正在尝试根据第一次出现的值重新组织一个数组(从而模拟与圆形数组类似的功能.)

例如,在下面的数组中,我希望第一次出现的值6成为新的第一个元素,而先前的元素成为后者:

所以:

int[] myArray = {2, 3, 6, 1, 7, 6};
Run Code Online (Sandbox Code Playgroud)

变为:

myArray = {6, 1, 7, 6, 2, 3};
Run Code Online (Sandbox Code Playgroud)

实现这一目标的"最佳"方式是什么?

Dan*_*ott 19

int[] myArray = { 2, 3, 6, 1, 7, 6 };
myArray = myArray
            .SkipWhile(i => i != 6)
            .Concat(myArray.TakeWhile(i => i != 6))
            .ToArray();
Run Code Online (Sandbox Code Playgroud)

应该做的伎俩!

你需要使用System.Linq;

  • 这很奇怪:没有人读过规范.**你是唯一一个有正确答案**的人,而你正在投票.人们,OP说"第一次出现6值成为新的第一个元素" - 没有将数组转移到已知数量的单元格中. (2认同)
  • @Kobi:这正是我的解决方案和Jon Skeets解决方案正在做的事情.说"值X的第一次出现应该是第一次"等于说"在X之前跳过所有,从那里复制,从0追加到第一次出现的X".虽然这里有错误的答案,但这个答案并不是唯一正确的答案! (2认同)

Jon*_*eet 9

Thorsten的解决方案创建了一个新阵列; 这是一个就地版本,它只创建一个与旋转大小一样大的临时数组:

public static void RotateLeft<T>(T[] array, int places)
{
    T[] temp = new T[places];
    Array.Copy(array, 0, temp, 0, places);
    Array.Copy(array, places, array, 0, array.Length - places);
    Array.Copy(temp, 0, array, array.Length - places, places);
}
Run Code Online (Sandbox Code Playgroud)

我敢肯定,这可能只是一个单一的临时缓冲区的项目来完成,但它会更加复杂:)

作为一种效率衡量标准,这里是"向左旋转一个地方"的快捷方式:

public static void RotateLeft<T>(T[] array)
{
    T temp = array[0];
    Array.Copy(array, 0, array, 1, array.Length - 1);
    array[array.Length-1] = temp;
}
Run Code Online (Sandbox Code Playgroud)

  • 它确实创建了一个新的,但是它创建了一个与要跳过的位数一样大的数组,而你的想法创建了一个与原始数组一样大的数组.`skip <array.Length`将始终保持(因为任何更大的`skip`将等同于`skip%array.Length`,它再次小于`array.Length`)所以Jon的实现使用更少的空间.大型阵列和小型旋转的空间要小得多,而大型旋转或小型阵列的空间则少得多. (2认同)

Tho*_*mar 5

您可以执行以下操作:

  1. 创建与原始大小相同的新数组
  2. 确定您的"开始索引"
  3. 用于Array.Copy()将从开始索引到源数组末尾的所有内容复制到目标数组
  4. 使用Array.Copy()一切从0复制到启动源阵列的索引到目标数组的末尾

这样,您就可以得到您所期望的源数组的副本.

Array.Copy()但是,您必须使用各种重载,因为我现在不知道确切的参数值.


Jor*_*ren 5

首先,进行线性搜索以查找要创建第一个元素的值的第一个匹配项:

// value contains the value to find.

int skip;
for (int i = 0; i < array.Length; i++)
{
    if (array[i] == value)
    {
        skip = i;
        break;
    }
}

// skip contains the index of the element to put at the front.
// Equivalently, it is the number of items to skip.
// (I chose this name for it because it makes the subtractions
// in the Array.Copy implementation more intuitive.)
Run Code Online (Sandbox Code Playgroud)

你想改变实际的阵列吗?然后做Thorsten Dittmar建议的事情:

int[] array = new int[] { 2, 3, 6, 1, 7, 6 };
int[] result = new int[array.Length];

int skip = 2; // So that array[skip] will be result[0] at the end

Array.Copy(array, skip, result, 0, array.Length - skip);
Array.Copy(array, 0, result, array.Length - skip, skip);
Run Code Online (Sandbox Code Playgroud)

您是否只想以新的顺序查看数组,而不做其他任何事情?然后将其编入索引:

array[(i + skip) % array.Length]  // Instead of array[i]
Run Code Online (Sandbox Code Playgroud)

编辑:只是为了笑,实现Jon Skeet建议实现副本,同时只使用一个缓冲区值(sourceValue):

// GCD gives the greatest common divisor
int gcd = GCD(array.Length, skip);

// period is the length of the permutation cycles in our rotation.
int period = array.Length / gcd;

int max = array.Length / period;
for (int i = 0; i < max; i++)
{
    int sourceIndex = i;
    int sourceValue = array[sourceIndex];

    for (int n = 1; n <= period; n++)
    {
        int destinationIndex = (sourceIndex + array.Length - skip) % array.Length;

        int temp = array[destinationIndex];
        array[destinationIndex] = sourceValue;
        sourceValue = temp;

        sourceIndex = destinationIndex;
    }
}
Run Code Online (Sandbox Code Playgroud)