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

时间:2021-10-25 14:04:36

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

列表显示我有一个列表列表 {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)

我的问题是,最简单的方法是什么(在简短的代码中,c# 4 Linq就绪),并且不会受到性能的影响(合理的性能)

Thanks.

谢谢。

16 个解决方案

#1


45  

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.

**我不确定将列表转换为队列的性能,但人们对我的评论投了赞成票,所以我把这个作为答案。

#2


63  

List<T>

< T >列表

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

最简单的方法(对于列表 )是:

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

Performance is nasty though - O(n).

性能是令人讨厌的- 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>

LinkedList < T >

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

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

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

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

这是O(1)因为每个操作都是常数时间。

Queue<T>

队列< T >

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

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

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.

虽然我找不到任何关于这个问题的性能特征的文档,但是我希望队列 使用一个数组和一个索引作为“虚拟起点”实现——在这种情况下,这是另一个O(1)解决方案。

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.)

注意,在所有这些情况下,您都希望首先检查列表是否为空。(你可以认为这是一个错误,或者是一个禁忌。)

#3


17  

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

#4


8  

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.

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

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
}

#5


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.

rot是要旋转的点数——必须小于输入列表中的元素数。

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

正如@cadrell0答案所示,如果这就是您对列表所做的一切,那么应该使用队列而不是列表。

#6


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.

尽管我更喜欢Jon Skeet的答案。

#7


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

#8


1  

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.

我的解决方案可能太基础了(我不想说它太差劲了…),而不是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;
}

#9


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

#10


1  

You can play nice in .net framework.

你可以在。net框架中玩得很好。

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...

我理解您想要做的是一个迭代行为,而不是一个新的集合类型;所以我建议你试试这个基于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;
    }
}
  • 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.

如果想更进一步,可以创建一个循环列表,并保持相同的枚举数,以便在像示例中那样旋转时跳过skip()。

#11


0  

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:

它们当然很简单(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); // e.g. 236
}

#12


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

#13


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

#14


0  

Using Linq,

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

#15


-1  

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

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

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

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

#16


-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.

当我从控制台读取数据时,基本上就是将值添加到数组中。

#1


45  

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.

**我不确定将列表转换为队列的性能,但人们对我的评论投了赞成票,所以我把这个作为答案。

#2


63  

List<T>

< T >列表

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

最简单的方法(对于列表 )是:

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

Performance is nasty though - O(n).

性能是令人讨厌的- 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>

LinkedList < T >

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

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

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

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

这是O(1)因为每个操作都是常数时间。

Queue<T>

队列< T >

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

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

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.

虽然我找不到任何关于这个问题的性能特征的文档,但是我希望队列 使用一个数组和一个索引作为“虚拟起点”实现——在这种情况下,这是另一个O(1)解决方案。

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.)

注意,在所有这些情况下,您都希望首先检查列表是否为空。(你可以认为这是一个错误,或者是一个禁忌。)

#3


17  

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

#4


8  

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.

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

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
}

#5


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.

rot是要旋转的点数——必须小于输入列表中的元素数。

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

正如@cadrell0答案所示,如果这就是您对列表所做的一切,那么应该使用队列而不是列表。

#6


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.

尽管我更喜欢Jon Skeet的答案。

#7


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

#8


1  

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.

我的解决方案可能太基础了(我不想说它太差劲了…),而不是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;
}

#9


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

#10


1  

You can play nice in .net framework.

你可以在。net框架中玩得很好。

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...

我理解您想要做的是一个迭代行为,而不是一个新的集合类型;所以我建议你试试这个基于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;
    }
}
  • 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.

如果想更进一步,可以创建一个循环列表,并保持相同的枚举数,以便在像示例中那样旋转时跳过skip()。

#11


0  

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:

它们当然很简单(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); // e.g. 236
}

#12


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

#13


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

#14


0  

Using Linq,

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

#15


-1  

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

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

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

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

#16


-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.

当我从控制台读取数据时,基本上就是将值添加到数组中。