如何在C#中将数组中的所有元素向上移动一个位置?

4

我正在尝试编写一个方法,将数组中第一个和最后一个字符之间的所有字符向上移动一个位置。此外,第一个到最后一个字符必须“移动”到数组的第二个位置([1])。简而言之,我希望'abcdef'变成'aebcdf'。 以下是我的解决方案:

                if (myArray.Length > 3)
            {
                char savechar = myArray[myArray.Length - 2];
                for (int t = 1; t < (myArray.Length - 2); t++)
                {
                    myArray[t++] = myArray[t];
                }
                myArray[1] = savechar;
            }

问题在于,它只是将第二个字符移到末尾,而不是将所有字符向上移动一个位置。(我知道它为什么这样做,但我不知道该如何解决)。有人能帮忙吗?


1
将倒数第二个元素(元素n-1; e)存储在临时变量中。使用一次 Array.Copy 调用来移动元素1、...、n-2。将临时变量中的元素放置在数组插槽#1中。完成... - user2819245
2
我建议初学者程序员先在纸上解决这个问题。实际上拿一张纸、一支铅笔和一块橡皮,在纸上写出数组,然后模拟需要执行的操作。仔细记录你在途中所做的每一个小步骤,然后仔细将该算法转换为代码。 - Eric Lippert
2
此外:现在就要改掉在另一个表达式中使用++的习惯。这样做对你没有任何好处,只会使你的算法更难理解和更难正确实现。 - Eric Lippert
谢谢您的建议 @EricLippert :) - Miel Elhorst
变量需要是一个数组吗?如果您计划像这样移动元素,您最好使用 List<char>,它将在您 添加移除 其他元素时进行转移。或者在移动完成后使用临时列表,并将其 转换回数组 - John Wu
显示剩余4条评论
7个回答

2
  1. 从结尾开始处理,这样就不会复制已经更改的字符。
  2. 我认为你不打算在循环内使用 "++"。这会改变 t 的值,没有必要。

以下是最终代码:

if (myArray.Length > 3)
{
    char savechar = myArray[myArray.Length - 2];
    for (int t = myArray.Length - 2; t > 1; t--)
    {
        myArray[t] = myArray[t-1];
    }
    myArray[1] = savechar;
}

@meilelhorst:这正是我在评论中所描述的。看看你能否从评论中弄清楚如何做到这一点,而不用看这段代码。 - Flydog57
1
@Flydog57 谢谢你们两个!我在想从后往前是否会有所不同,很高兴看到确实有区别。我会尝试自己重写几次代码,以便更好地理解它 ;) - Miel Elhorst
如果您听从Eric Lippert的建议(先在纸上练习),您将看到使此方法奏效(在纸上)的方法是从结尾开始并向前工作。如果您从开头开始,您没有任何“空插槽”可用于放置新移动的字符,而如果您从结尾开始,则可以将其移动到最近被清空的位置。 - Flydog57

2
这将得到所需的结果。请注意,由于使用了您的示例输入,因此没有长度检查。并且没有努力使其更加高效 ;)
var list = "abcdef".ToCharArray().ToList();    
var item = list.ElementAt(list.Count - 2);
list.RemoveAt(list.Count - 2);
list.Insert(1, item);
var reordered = string.Join(string.Empty, list);

1
这是我的看法:
for (int i = 1; i < input.Length - 1; i++)
{
  var temp = input[i];
  input[i] = input[input.Length - 2];
  input[input.Length - 2] = temp;
}

1
使用 Array.Copy:
if (myArray.Length > 3)
{
    char savechar = myArray[myArray.Length - 2];
    Array.Copy(myArray, 1, myArray, 2, myArray.Length - 3);
    myArray[1] = savechar;
}

0

这只适用于字符串,但它有效:

    var text = "abcdef";
    var shifted = text.First() + text.Substring(text.Length - 2, 1) + text.Substring(0, text.Length - 2) + text.Last();

0

这里是一个通用算法,可以将array循环移位shiftCount个元素,并跳过array开头和结尾的skippedElements个元素:

var array = new char[] {'a', 'b', 'c', 'd', 'e', 'f'};

var skippedElements = 1;
var shiftCount = 1;
bool shiftLeft = true;
if (shiftLeft)
{
    // shift left
    Array.Reverse(array, skippedElements, shiftCount);
    Array.Reverse(array, skippedElements + shiftCount, array.Length - skippedElements * 2 - shiftCount);
    Array.Reverse(array, skippedElements, array.Length - skippedElements - shiftCount);

}
else
{
    // shift right
    Array.Reverse(array, skippedElements, array.Length - skippedElements * 2);
    Array.Reverse(array, skippedElements + shiftCount,  array.Length - skippedElements * 2 - shiftCount);
    Array.Reverse(array, skippedElements, shiftCount);
}

这是数组旋转反转算法的修改版。它适用于skippedElements > 0的情况。它不需要额外的变量或内存。


0

就我个人而言,如果这是一个生产系统,我可能会选择NPCampbell的Array.Copy解决方案,但为了演示(以及一点点代码高尔夫乐趣),这里提供了使用Linq的解决方案:

var n = myArray.Length - 1;
var newArray = myArray.Select((_, i) => myArray[i % n > 0 ? (i > 1 ? i : n) - 1 : i]).ToArray();

这并不是最高效的选择,也绝对不是非常易读的,但它能正常工作。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接