76

Lists say I have a list List<int> {1,2,3,4,5}

Rotate means:

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

Maybe rotate is not the best word for this, but hope you understand what I means

My question, whats the easiest way (in short code, c# 4 Linq ready), and will not be hit by performance (reasonable performance)

Thanks.

Kris Harper
  • 5,672
  • 8
  • 51
  • 96
Eric Yin
  • 8,737
  • 19
  • 77
  • 118

17 Answers17

79

List<T>

The simplest way (for a List<T>) is to use:

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

Performance is nasty though - O(n).

Array

This is basically equivalent to the List<T> version, but more manual:

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

LinkedList<T>

If you could use a LinkedList<T> instead, that would be much simpler:

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

This is O(1) as each operation is constant time.

Queue<T>

cadrell0's solution of using a queue is a single statement, as Dequeue removes the element and returns it:

queue.Enqueue(queue.Dequeue());

While I can't find any documentation of the performance characteristic of this, I'd expect Queue<T> to be implemented using an array and an index as the "virtual starting point" - in which case this is another O(1) solution.

Note that in all of these cases you'd want to check for the list being empty first. (You could deem that to be an error, or a no-op.)

carlosdubusm
  • 1,063
  • 4
  • 11
  • 22
Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • 1
    I'd go with queue over linked list. A circular array just generally performs better in the average case, and in either situation all of the details are abstracted away by the language anyway. – Servy Mar 30 '12 at 18:11
  • 1
    @Servy: Yup, that's fair comment. A linked list allows the *reverse* rotation more easily, as .NET doesn't have a deque :( You could obviously build one easily though... – Jon Skeet Mar 30 '12 at 18:15
  • 1
    Isn't 'RemoveFirst()` void? The docs actually shows an example of exactly what the OP has asked: http://msdn.microsoft.com/en-us/library/ms132181.aspx. You have to get hold of the first node initially using linkedList.First? – Pero P. Mar 30 '12 at 18:21
  • @PeroPejovic: Apologies, yes. I wrote the example then checked, was disappointed to find that it wouldn't work, and forgot to fix it. – Jon Skeet Mar 30 '12 at 18:25
  • @JonSkeet Again, it's not the built in functionality, but it would be easy enough to make a circular array 'reverse' itself. You have pointers to the first and last, you just need to flip them and keep a boolean that indicates whether you're moving 'up' or 'down' in the array. It would add a fair bit of extra code mess, which is why I'm sure it's not done, but on a conceptual level reversing a circular array is still a very fast O(1) operation. – Servy Mar 30 '12 at 18:32
  • 1
    @JonSkeet Just realzied you meant reverse as in take from the back and put on the front, not reverse all elements. In either case, easy enough to implement with a circular array if you wanted, but not available through the exposed 'Queue' class. Agreed Deques would be nice though. – Servy Mar 30 '12 at 18:35
  • This is the best example of the influence a Collection can have over Big-O I have ever seen. Did a bit of digging and question asking to understand it, but really awesome. Thanks @JonSkeet – Thomas Dec 07 '16 at 17:37
50

You could implement it as a queue. Dequeue and Enqueue the same value.

**I wasn't sure about performance in converting a List to a Queue, but people upvoted my comment, so I'm posting this as an answer.

cadrell0
  • 17,109
  • 5
  • 51
  • 69
  • 8
    The only performance issues would be if the OP is doing anything else, because switching to a queue means that accessing anything but the first/last items are inefficient. – Servy Mar 30 '12 at 18:10
  • 1
    Have added the actual calls to my answer, as you hadn't included them and mine is pretty much collecting implementations :) Hope you don't mind. – Jon Skeet Mar 30 '12 at 18:11
  • @JonSkeet Not at all. Pure laziness is the reason I left it out of mine. – cadrell0 Mar 30 '12 at 18:12
28

I use this one:

public static List<T> Rotate<T>(this List<T> list, int offset)
{
    return list.Skip(offset).Concat(list.Take(offset)).ToList();
}
mrzli
  • 16,799
  • 4
  • 38
  • 45
9

It seems like some answerers have treated this as a chance to explore data structures. While those answers are informative and useful, they are not very Linq'ish.

The Linq'ish approach is: You get an extension method which returns a lazy IEnumerable that knows how to build what you want. This method doesn't modify the source and should only allocate a copy of the source if necessary.

public static IEnumerable<IEnumerable<T>> Rotate<T>(this List<T> source)
{
  for(int i = 0; i < source.Count; 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.Count; 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];
  }
}

Used as:

List<int> myList = new List<int>(){1, 2, 3, 4, 5};
foreach(IEnumerable<int> rotation in myList.Rotate())
{
  //do something with that rotation
}
Klaus Gütter
  • 11,151
  • 6
  • 31
  • 36
Amy B
  • 108,202
  • 21
  • 135
  • 185
3

How about this:

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

Where rot is the number of spots to rotate - which must be less than the number of elements in the input list.

As @cadrell0 answer shows if this is all you do with your list, you should use a queue instead of a list.

BrokenGlass
  • 158,293
  • 28
  • 286
  • 335
2

My solution maybe too basic (I wouldn't like to say it's lame...) and not LINQ'ish.
However, it has a pretty good 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;
}
zx485
  • 28,498
  • 28
  • 50
  • 59
ThomAce
  • 301
  • 4
  • 7
1

You can play nice in .net framework.

I understand that what you want to do is more up to be an iteration behavior than a new collection type; so I would suggest you to try this extension method based on IEnumerable, which will work with Collections, Lists and so on...

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;
    }
}
  • Reasonable performance
  • Flexible

If you want go further, make a CircularList and hold the same enumerator to skip the Skip() when rotating like in your sample.

Davi Fiamenghi
  • 1,237
  • 12
  • 28
1

My solution for Arrays:

    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);
    }
Pedro77
  • 5,176
  • 7
  • 61
  • 91
1

I've used the following extensions for this:

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

They're certainly easy (OP title request), and they've got reasonable performance (OP write-up request). Here's a little demo I ran in LINQPad 5 on an above-average-powered laptop:

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); // e.g. 236
}
William
  • 1,993
  • 2
  • 23
  • 40
1

You can use below code for left Rotation.

List<int> backUpArray = array.ToList();

for (int i = 0; i < array.Length; i++)
{
    int newLocation = (i + (array.Length - rotationNumber)) % n;
    array[newLocation] = backUpArray[i];
}
user3838082
  • 159
  • 1
  • 5
1

Try

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

Although, I like Jon Skeet's answer better.

Andy Evans
  • 6,997
  • 18
  • 72
  • 118
0

below is my approach. Thank you

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;
  }
  • Please add some explanation to your code to help readers understand why this solves the problem. Also, does this *really* add anything to the existing answers? – Gert Arnold Nov 11 '17 at 11:24
0
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;
}
EtherDragon
  • 2,679
  • 1
  • 18
  • 24
Arun
  • 1
0

Using Linq,

List<int> temp = new List<int>();     

 public int[] solution(int[] array, int range)
    {
        int tempLength = array.Length - range;

        temp = array.Skip(tempLength).ToList();

        temp.AddRange(array.Take(array.Length - range).ToList());

        return temp.ToArray();
    }
Vijayanath Viswanathan
  • 8,027
  • 3
  • 25
  • 43
0

If you're working with a string you can do this quite efficiently using ReadOnlySpans:

ReadOnlySpan<char> apiKeySchema = "12345";
const int apiKeyLength = 5;
for (int i = 0; i < apiKeyLength; i++)
{
    ReadOnlySpan<char> left = apiKeySchema.Slice(start: i, length: apiKeyLength - i);
    ReadOnlySpan<char> right = apiKeySchema.Slice(start: 0, length: i);
    Console.WriteLine(string.Concat(left, right));
}       

Output:

12345
23451
34512
45123
51234

Jeremy Thompson
  • 61,933
  • 36
  • 195
  • 321
-1

I was asked to reverse a character array with minimal memory usage.

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

Method:

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

How about using modular arithmetic :

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

So basically adding the values to the array when I am reading from console.

Naphstor
  • 2,356
  • 7
  • 35
  • 53
  • There's no mention of console input in the question. For this to be a valid answer you need to start with `List {1,2,3,4,5}` and show how your code can do the rotation. – Enigmativity Nov 07 '16 at 01:29
  • I believe the question says "Lets say i have a list". It does not say how the list is prepared. What I am trying to show is while preparing your input list, or basically while adding data to your input list itself you can use modular arithmetic and solve the problem. Even if you want to work with existing list, you can still use above logic to prepare new rotated list. – Naphstor Nov 08 '16 at 17:58
  • 1
    I would suggest that you explicitly show how to do this from the list. Showing something extra is probably not worthwhile. – Enigmativity Nov 08 '16 at 20:46
  • I agree on that. But I was just giving an idea of implementing the solution in different way. – Naphstor Nov 09 '16 at 21:32
  • Showing it in a different way is probably not worthwhile. You have an interesting answer but it is hard to understand how it applies to the question given that it doesn't show how to do it from the list. – Enigmativity Nov 09 '16 at 21:37