Самый легкий способ Повернуть Список в 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), и не будет поражено производительностью (разумная производительность)

Спасибо.

62
задан 30 March 2012 в 23:53

16 ответов

Вы могли реализовать его как очередь. Исключите из очереди и Ставьте в очередь то же значение.

** я не был уверен в производительности в преобразовании Списка Очереди, но людей upvoted мой комментарий, таким образом, я отправляю это как ответ.

46
ответ дан 31 October 2019 в 13:31

Как насчет того, чтобы использовать арифметику в остаточных классах:

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

Так в основном добавление значений к массиву, когда я читаю из консоли.

-1
ответ дан 31 October 2019 в 13:31

Меня попросили инвертировать символьный массив с минимальным использованием памяти.

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;
    }
}
-1
ответ дан 31 October 2019 в 13:31

Использование 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();
    }
0
ответ дан 31 October 2019 в 13:31
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;
}
0
ответ дан 31 October 2019 в 13:31

ниже мой подход. Спасибо

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;
  }
0
ответ дан 31 October 2019 в 13:31

Я использовал следующие расширения для этого:

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 на above-average-powered ноутбуке:

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
}
0
ответ дан 31 October 2019 в 13:31

Можно использовать ниже кода для левого Вращения.

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

for (int i = 0; i < array.Length; i++)
{
    int newLocation = (i + (array.Length - rotationNumber)) % n;
    array[newLocation] = backUpArray[i];
}
1
ответ дан 31 October 2019 в 13:31

Мое решение, возможно, слишком основное (я не хотел бы говорить, что это - Ламе...), и не LINQ'ish.
Однако это имеет довольно хорошую производительность.

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;
}
2
ответ дан 31 October 2019 в 13:31

Мое решение для Массивов:

    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);
    }
1
ответ дан 31 October 2019 в 13:31

Можно играть по правилам в платформе .NET.

я понимаю, что то, что Вы хотите сделать, больше, чтобы быть итеративным поведением, чем новый тип набора; таким образом, я предложил бы, чтобы Вы попробовали этот дополнительный метод на основе IEnumerable, который будет работать с Наборами, Списки и так далее...

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;
    }
}
  • Разумная производительность
  • Гибкий

, Если Вы хотите, идет далее, делает CircularList и содержит тот же перечислитель для пропуска Skip() при вращении как в образце.

1
ответ дан 31 October 2019 в 13:31

Попробуйте

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 лучше.

1
ответ дан 31 October 2019 в 13:31

Как насчет этого:

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

, Где rot количество пятен для вращения - который должен быть меньше, чем число элементов в эти input список.

, Поскольку @cadrell0 отвечают на шоу, если это - все, что Вы делаете со своим списком, необходимо использовать очередь вместо списка.

3
ответ дан 31 October 2019 в 13:31

Кажется, что некоторые отвечающие стороны рассматривали это как шанс исследовать структуры данных. В то время как те ответы информативны и полезны, они не очень Linq'ish.

подход Linq'ish: Вы получаете дополнительный метод, который возвращает ленивый IEnumerable, который знает, как создать то, что Вы хотите. Этот метод не изменяет источник и должен только выделить копию источника при необходимости.

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
}
8
ответ дан 31 October 2019 в 13:31

Я использую этого:

public static List<T> Rotate<T>(this List<T> list, int offset)
{
    return list.Skip(offset).Concat(list.Take(offset)).ToList();
}
23
ответ дан 31 October 2019 в 13:31

List<T>

самый простой путь (для List<T>) состоит в том, чтобы использовать:

int first = list[0];
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 использования очереди является отдельный оператор, поскольку Dequeue удаляет элемент и возвраты это:

queue.Enqueue(queue.Dequeue());

, В то время как я не могу найти документацию рабочей характеристики этого, я был бы ожидать Queue<T> быть реализованным с помощью массива и индекса как "виртуальная начальная точка" - в этом случае это - другой O (1) решение.

Примечание, что во всех этих случаях Вы хотели бы проверить на список, являющийся пустым сначала. (Вы могли считать что быть ошибкой, или нет.)

67
ответ дан 31 October 2019 в 13:31

Другие вопросы по тегам:

Похожие вопросы: