Reputation: 1637
This is a basic question ( I am new to C#), but is there an efficient way to move the first element to the end of the array in C#?
I found this question, which describes the .rotate
method in ruby, but I have been unable to find a similar method in C#.
If I have an array:
[1, 2, 3, 4, 5]
Is there a function in C# that returns:
[2, 3, 4, 5, 1]
Thanks in advance!
EDIT: Answer
The best solution is to use LinkedList<T>
as many of you suggested and as shown in Alex's answer. His suggested solution was using:
list.AddLast(list.RemoveFirst());
which can be run in a for loop:
void func<T>(LinkedList<T> list, int rotate) {
for(var i = 0; i < rotate; i++) {
list.AddLast(list.RemoveFirst());
}
}
Thank you all for your help!
Upvotes: 5
Views: 14718
Reputation: 1957
If you use LinkedList<T>
instead of array<T>
you could just use this:
list.AddLast(list.RemoveAndGetFirst());
Edit: RemoveAndGetFirst()
can be an extension like:
LinkedListNode<T> elem = list.First;
list.RemoveFirst();
return elem;
Complexity O(1)
. When you perform this multiple times:
void func<T>(LinkedList<T> list, int rotate) {
for(var i = 0; i < rotate; i++) {
list.AddLast(list.RemoveFirst());
}
}
You will have a complexity of O(N)
[where N
is the number of rotations]. This is, performance wise, the best solution.
If you really need to use arrays this could be a naiv solution:
var tmp = list[0];
for(var i = 1; i < list.Length; i++) {
list[i - 1] = list[i];
}
list[list.Length - 1] = tmp;
(Be aware there are no range checks)
But this will be very time consuming if you need to do this often. If you perform this multiple times:
void func<T>(T[] list, int rotate) {
for(var j = 0; j < rotate; j++) {
var tmp = list[0];
for(var i = 1; i < list.Length; i++) {
list[i - 1] = list[i];
}
list[list.Length - 1] = tmp;
}
}
You will end up with O(N^2) = O(N * M)
[where N
is the number of elements and M
the number of rotations]. This would be really bad. A better approach, if you know in advance you'll perform this often would be:
void func<T>(T[] list, int rotate {
for(var j = 0; j < list.Length; j++) {
var tmp = list[j];
var ix = (rotate + j) % list.Length;
list[j] = list[ix];
list[ix] = tmp;
}
}
Which will result in O(N)
[where N
is the number of elements].
As others already suggested, it's a good idea to write an extension method if you need this at multiple locations.
Upvotes: 7
Reputation: 1642
Try this one..
using System;
public class Program
{
public static int[] arrData = new int[5]{1,2,3,4,5};
public static void Main()
{
Console.WriteLine("\nOriginal array\n");
foreach(var item in arrData)
{
Console.WriteLine(item.ToString());
}
Console.WriteLine("\nShift to last\n");
arrData = shiftLast(arrData);
foreach(var item in arrData)
{
Console.WriteLine(item.ToString());
}
}
public static int[] shiftLast(int[] arr)
{
int last = arr[arr.Length - 1];
int first= arr[0];
arr[arr.Length - 1] = first;
arr[0] = last;
return arr;
}
}
Try to run here
Cheers
Upvotes: 2
Reputation: 24280
It's starting to look like Code Golf now :-) so here's my contribution:
var x = new[] { 1, 2, 3, 4, 5 };
var y = Enumerable.Range(1, x.Length).Select(i => x[i % x.Length]).ToArray();
Upvotes: 3
Reputation: 13079
Using Array.Copy
to copy elements to itself just shifted ;)
var array = new int[]{1, 2, 3, 4, 5};
var head = array[0];
Array.Copy(array, 1, array, 0, array.Length- 1);
array[array.Length - 1] = head;
And as an extension method returning a new array just like the Ruby version
static class ArrayRotateExtensions {
public static int[] Rotate(this int[] arr, int offset) {
var l = arr.Length;
var rot = new int[l];
if (offset == 0) {
Array.Copy(arr, 0, rot, 0, l);
return rot;
}
// constrain rotations greater than array length, it's the same result anyway
offset = offset % l;
// negative rotation is equal to positive rotation length - offset
if (offset < 0) {
offset += l;
}
Array.Copy(arr, offset, rot, 0, l - offset);
Array.Copy(arr, 0, rot, l - offset, offset);
return rot;
}
}
This will allow you to do
var array = new int[]{1, 2, 3, 4, 5};
var rotated = array.Rotate(1);
Plus rotation by any arbitrary amount.
Only downside is you'd have to add a version for every array type you'd like to use it on.
Upvotes: 4
Reputation: 13676
The reason why there is no function like that in LINQ
is most likely that people who developed LINQ
didn't think it's something that is an absolute must...
If you really need that you can create an extension method. Something along the lines of:
public static IEnumerable<T> Rotate<T>(this IEnumerable<T> elements, int number)
{
var elemetsList = elements as IList<T> ?? elements.ToList();
var list = new List<T>(elemetsList.Count);
if (number > elemetsList.Count - 1)
{
throw new ArgumentException(nameof(number));
}
for (int i = number; i < elemetsList.Count; i++)
{
list.Add(elemetsList[i]);
}
for (int i = 0; i < number; i++)
{
list.Add(elemetsList[i]);
}
return list;
}
And use it:
var arr = new int[] {1, 2, 3, 4, 5};
int[] result = arr.Rotate(1).ToArray();
int[] result2 = arr.Rotate(3).ToArray();
Output:
2 3 4 5 1
4 5 1 2 3
This solution is fairly efficient. For an array 500 000 in length it took only 7ms on my machine to execute.
Upvotes: 2
Reputation: 1258
As far as I know there isn't such method for an array. If you do this often perhaps you should consider using a different object (List<T>
, Stack<T>
, etc).
But even with an array you can implement simple functionality like this using extension methods:
public static int[] MoveFirstToLast (this int[] obj)
{
int movedValue = obj[0];
(int i = 1; i < obj.Length; i++)
{
obj[i - 1] = obj[i];
}
obj[obj.Length - 1] = movedValue;
return obj;
}
And then the use is just:
int[] myArray = //whatever;
int[] changedArray = myArray.MoveFirstToLast();
Upvotes: 1
Reputation: 880
Maybe like this -
static void Main( string[] args ) {
Console.WriteLine(string.Join(", ", getArray(new int[] { 1, 2, 3, 4, 5 })));
Console.Read();
return;
}
static int[] getArray( int[] arr ) {
List<int> O = new List<int>();
for (int x = 1, l = arr.Length; x < l; x++) {
O.Add(arr[x]);
}
O.Add(arr[0]);
return O.ToArray();
}
Upvotes: 1
Reputation: 47036
There are many ways to achieve this. One way would be:
var result = arr.Skip(1).Concat(arr.Take(1))
Upvotes: 11