最简单的方法来旋转c#中的列表

列表说我有一个列表List<int> {1,2,3,4,5}

旋转意味着:

 => {2,3,4,5,1} => {3,4,5,1,2} => {4,5,1,2,3} 

也许旋转不是这个最好的词,但希望你明白我的意思

我的问题,最简单的方法是什么(简而言之,C#4 Linq准备好了),并不会受到性能(合理的性能)

谢谢。

你可以实现它作为一个队列。 出列和入队相同的值。

**我不确定将列表转换为队列的性能,但是有人赞成我的评论,所以我将其作为回答发表。

List<T>

最简单的方法(对于List<T> )是使用:

 int first = list.RemoveAt(0); list.Add(first); 

性能是令人讨厌的 – O(n)。

排列

这基本上相当于List<T>版本,但更多的手册:

 int first = array[0]; Array.Copy(array, 1, array, 0, array.Length - 1); array[array.Length - 1] = first; 

LinkedList<T>

如果你可以使用LinkedList<T> ,那就简单多了:

 int first = linkedList.First; linkedList.RemoveFirst(); linkedList.AddLast(first); 

这是O(1),因为每个操作是恒定的时间。

Queue<T>

cadrell0使用队列的解决scheme是单个语句,因为Dequeue删除元素返回它:

 queue.Enqueue(queue.Dequeue()); 

虽然我找不到任何有关此性能特性的文档,但是我期望 Queue<T>使用数组和索引作为“虚拟起点”来实现 – 在这种情况下,这是另一个O(1)解。

请注意,在所有这些情况下,您首先需要检查列表是否为空。 (你可能认为这是一个错误,或者是一个没有操作。)

我使用这个:

 public static List<T> Rotate<T>(this List<T> list, int offset) { return list.Skip(offset).Concat(list.Take(offset)).ToList(); } 

似乎有些回答者将此视为探索数据结构的机会。 虽然这些答案是丰富和有用的,他们不是很Linq'ish。

Linq'ish的方法是:你得到一个扩展方法返回一个懒惰的IEnumerable知道如何build立你想要的。 此方法不会修改源,并且只应根据需要分配源的副本。

 public static IEnumerable<IEnumerable<T>> Rotate<T>(this List<T> source) { for(int i = 0; i < source.Length; i++) { yield return source.TakeFrom(i).Concat(source.TakeUntil(i)); } } //similar to list.Skip(i-1), but using list's indexer access to reduce iterations public static IEnumerable<T> TakeFrom<T>(this List<T> source, int index) { for(int i = index; i < source.Length; i++) { yield return source[i]; } } //similar to list.Take(i), but using list's indexer access to reduce iterations public static IEnumerable<T> TakeUntil<T>(this List<T> source, int index) { for(int i = 0; i < index; i++) { yield return source[i]; } } 

用作:

 List<int> myList = new List<int>(){1, 2, 3, 4, 5}; foreach(IEnumerable<int> rotation in myList.Rotate()) { //do something with that rotation } 

这个怎么样:

 var output = input.Skip(rot) .Take(input.Count - rot) .Concat(input.Take(rot)) .ToList(); 

其中rot是要旋转的点数 – 它必须小于input列表中元素的数量。

正如@ cadrell0答案显示,如果这是你所做的所有清单,你应该使用一个队列,而不是一个列表。

尝试

 List<int> nums = new List<int> {1,2,3,4,5}; var newNums = nums.Skip(1).Take(nums.Count() - 1).ToList(); newNums.Add(nums[0]); 

虽然,我更喜欢Jon Skeet的回答。

我的arrays解决scheme:

  public static void ArrayRotate(Array data, int index) { if (index > data.Length) throw new ArgumentException("Invalid index"); else if (index == data.Length || index == 0) return; var copy = (Array)data.Clone(); int part1Length = data.Length - index; //Part1 Array.Copy(copy, 0, data, index, part1Length); //Part2 Array.Copy(copy, part1Length, data, 0, index); } 

我的解决scheme可能太基础(我不想说这是蹩脚的…),而不是LINQ'ish。
但是,它有不错的performance。

 int max = 5; //the fixed size of your array. int[] inArray = new int[5] {0,0,0,0,0}; //initial values only. void putValueToArray(int thisData) { //let's do the magic here... Array.Copy(inArray, 1, inArray, 0, max-1); inArray[max-1] = thisData; } 

您可以使用下面的代码左旋转。

 List<int> backUpArray = array.ToList(); for (int i = 0; i < array.Length; i++) { int newLocation = (i + (array.Length - rotationNumber)) % n; array[newLocation] = backUpArray[i]; } 

你可以在.net框架中玩。

我明白,你想要做的是更多的迭代行为比新的集合types; 所以我build议你尝试这种基于IEnumerable的扩展方法,这将与collections,列表等工作…

 class Program { static void Main(string[] args) { int[] numbers = { 1, 2, 3, 4, 5, 6, 7 }; IEnumerable<int> circularNumbers = numbers.AsCircular(); IEnumerable<int> firstFourNumbers = circularNumbers.Take(4); // 1 2 3 4 IEnumerable<int> nextSevenNumbersfromfourth = circularNumbers .Skip(4).Take(7); // 4 5 6 7 1 2 3 } } public static class CircularEnumerable { public static IEnumerable<T> AsCircular<T>(this IEnumerable<T> source) { if (source == null) yield break; // be a gentleman IEnumerator<T> enumerator = source.GetEnumerator(); iterateAllAndBackToStart: while (enumerator.MoveNext()) yield return enumerator.Current; enumerator.Reset(); if(!enumerator.MoveNext()) yield break; else yield return enumerator.Current; goto iterateAllAndBackToStart; } } 
  • 合理的performance
  • 灵活

如果你想进一步,做一个CircularList并保持相同的枚举器跳过像样本旋转时Skip()

我为此使用了以下扩展:

 static class Extensions { public static IEnumerable<T> RotateLeft<T>(this IEnumerable<T> e, int n) => n >= 0 ? e.Skip(n).Concat(e.Take(n)) : e.RotateRight(-n); public static IEnumerable<T> RotateRight<T>(this IEnumerable<T> e, int n) => e.Reverse().RotateLeft(n).Reverse(); } 

他们当然很容易(OP标题请求),他们已经得到了合理的性能(OP写入请求)。 这里有一个我在LINQPad 5上运行的一个小例子,它是一款平均水平高于笔记本电脑的笔记本:

 void Main() { const int n = 1000000; const int r = n / 10; var a = Enumerable.Range(0, n); var t = Stopwatch.StartNew(); Console.WriteLine(a.RotateLeft(r).ToArray().First()); Console.WriteLine(a.RotateLeft(-r).ToArray().First()); Console.WriteLine(a.RotateRight(r).ToArray().First()); Console.WriteLine(a.RotateRight(-r).ToArray().First()); Console.WriteLine(t.ElapsedMilliseconds); // eg 236 } 

下面是我的做法。 谢谢

 public static int[] RotationOfArray(int[] A, int k) { if (A == null || A.Length==0) return null; int[] result =new int[A.Length]; int arrayLength=A.Length; int moveBy = k % arrayLength; for (int i = 0; i < arrayLength; i++) { int tmp = i + moveBy; if (tmp > arrayLength-1) { tmp = + (tmp - arrayLength); } result[tmp] = A[i]; } return result; } 
 public static int[] RightShiftRotation(int[] a, int times) { int[] demo = new int[a.Length]; int d = times,i=0; while(d>0) { demo[d-1] = a[a.Length - 1 - i]; d = d - 1; i = i + 1; } for(int j=a.Length-1-times;j>=0;j--) { demo[j + times] = a[j]; } return demo; } 

我被要求用最less的内存使用来反转字符数组。

char[] charArray = new char[]{'C','o','w','b','o','y'};

方法:

 static void Reverse(ref char[] s) { for (int i=0; i < (s.Length-i); i++) { char leftMost = s[i]; char rightMost = s[s.Length - i - 1]; s[i] = rightMost; s[s.Length - i - 1] = leftMost; } } 

如何使用模块化algorithm:

 public void UsingModularArithmetic() { string[] tokens_n = Console.ReadLine().Split(' '); int n = Convert.ToInt32(tokens_n[0]); int k = Convert.ToInt32(tokens_n[1]); int[] a = new int[n]; for(int i = 0; i < n; i++) { int newLocation = (i + (n - k)) % n; a[newLocation] = Convert.ToInt32(Console.ReadLine()); } foreach (int i in a) Console.Write("{0} ", i); } 

所以,当我从控制台读取基本上添加到数组的值。