Les listes indiquent que j'ai une liste List<int> {1,2,3,4,5}
Rotation signifie:
=> {2,3,4,5,1} => {3,4,5,1,2} => {4,5,1,2,3}
Peut-être que tourner n'est pas le meilleur mot pour cela, mais j'espère que vous comprenez ce que je veux dire
Ma question, quelle est la manière la plus simple (en short code, c # 4 Linq ready), et ne sera pas touchée par les performances (performances raisonnables)
Merci.
Vous pouvez l'implémenter en tant que file d'attente. Retirer et mettre en file d'attente la même valeur.
** Je n'étais pas sûr des performances de conversion d'une liste en file d'attente, mais les gens ont voté pour mon commentaire, donc je poste ceci comme réponse.
La manière la plus simple (pour une List<T>
) consiste à utiliser:
int first = list[0];
list.RemoveAt(0);
list.Add(first);
Cependant, la performance est mauvaise - O (n).
Tableau
Ceci est fondamentalement équivalent au List<T>
version, mais plus manuelle:
int first = array[0];
Array.Copy(array, 1, array, 0, array.Length - 1);
array[array.Length - 1] = first;
Si vous pouviez utiliser un LinkedList<T>
à la place, ce serait beaucoup plus simple:
int first = linkedList.First;
linkedList.RemoveFirst();
linkedList.AddLast(first);
C'est O(1) car chaque opération est à temps constant.
la solution de cadrell0 d'utiliser une file d'attente est une seule instruction, car Dequeue
supprime l'élément et le renvoie:
queue.Enqueue(queue.Dequeue());
Bien que je ne trouve aucune documentation sur les caractéristiques de performance de cela, je voudrais attendreQueue<T>
à implémenter en utilisant un tableau et un index comme "point de départ virtuel" - auquel cas c'est une autre solution O(1)).
Notez que dans tous ces cas, vous voudrez d'abord vérifier que la liste est vide. (Vous pouvez considérer cela comme une erreur ou un non-fonctionnement.)
J'utilise celui-ci:
public static List<T> Rotate<T>(this List<T> list, int offset)
{
return list.Skip(offset).Concat(list.Take(offset)).ToList();
}
Il semble que certains répondeurs aient traité cela comme une chance d'explorer les structures de données. Bien que ces réponses soient informatives et utiles, elles ne sont pas très linq'ish.
L'approche Linq'ish est la suivante: vous obtenez une méthode d'extension qui retourne un IEnumerable paresseux qui sait comment construire ce que vous voulez. Cette méthode ne modifie pas la source et ne doit allouer une copie de la source que si nécessaire.
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];
}
}
Utilisé comme:
List<int> myList = new List<int>(){1, 2, 3, 4, 5};
foreach(IEnumerable<int> rotation in myList.Rotate())
{
//do something with that rotation
}
Que dis-tu de ça:
var output = input.Skip(rot)
.Take(input.Count - rot)
.Concat(input.Take(rot))
.ToList();
Où rot
est le nombre de points à faire pivoter - qui doit être inférieur au nombre d'éléments dans la liste input
.
Comme la réponse @ cadrell0 montre si c'est tout ce que vous faites avec votre liste, vous devez utiliser une file d'attente au lieu d'une liste.
Ma solution est peut-être trop basique (je ne voudrais pas dire que c'est boiteux ...) et pas LINQ'ish.
Cependant, ses performances sont plutôt bonnes.
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;
}
Vous pouvez jouer à Nice dans le cadre .net.
Je comprends que ce que vous voulez faire est plus un comportement d'itération qu'un nouveau type de collection; Je vous suggère donc d'essayer cette méthode d'extension basée sur IEnumerable, qui fonctionnera avec les collections, les listes, etc.
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;
}
}
Si vous voulez aller plus loin, faites un CircularList
et maintenez le même énumérateur pour ignorer la Skip()
lors de la rotation comme dans votre exemple.
Essayer
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]);
Cependant, j'aime mieux la réponse de Jon Skeet.
Vous pouvez utiliser le code ci-dessous pour la rotation à gauche.
List<int> backUpArray = array.ToList();
for (int i = 0; i < array.Length; i++)
{
int newLocation = (i + (array.Length - rotationNumber)) % n;
array[newLocation] = backUpArray[i];
}
Ma solution pour les tableaux:
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);
}
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;
}
ci-dessous est mon approche. Je vous remercie
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;
}
J'ai utilisé les extensions suivantes pour cela:
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();
}
Ils sont certainement faciles (demande de titre OP) et leurs performances sont raisonnables (demande de rédaction OP). Voici une petite démo que j'ai exécutée dans LINQPad 5 sur un ordinateur portable de puissance supérieure à la moyenne:
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
}
À l'aide de 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();
}