代码之家  ›  专栏  ›  技术社区  ›  satyajit

使用LINQ语法旋转数组

  •  1
  • satyajit  · 技术社区  · 14 年前

    我正在解决这个旋转数组的问题,并得到了算法和代码

     int[] Rotate(int[] ar,int k)
            {
                if (k <= 0 || k > ar.Length - 1)
                    return ar;
                Reverse(ar, 0, k - 1);
                Reverse(ar, k, ar.Length - 1);
                Reverse(ar, 0, ar.Length - 1);
                return ar;            
            }
    
     void Reverse(int[] ar,int start, int end)
            {
                while (start < end)
                {
                    int temp = ar[start];
                    ar[start] = ar[end];
                    ar[end] = temp;
                    start++;
                    end--;
                }
            }
    

    现在我想在LINQ中做这个,我得到了下面的代码,我认为这可以做得更好。

     int[] Rotate(int[] ar,int k)
        {
            if (k <= 0 || k > ar.Length - 1)
                return ar;
            int[] ar1=ar.Take(k-1).Reverse().ToArray();
            int[] ar2=ar.Skip(k - 1).Take(ar.Length - k+1).Reverse().ToArray();
            int[] ar3 = ar1.Concat(ar2).Reverse().ToArray();
            return ar3;
        }
    

    这是一个著名的算法从编程珍珠- http://books.google.com/books?id=kse_7qbWbjsC&lpg=PA14&ots=DfzTzQCSar&dq=rotate%20an%20array%20programming%20pearls&pg=PA14#v=onepage&q&f=false

    一般来说,如何发展我的LINQ技能,如果给我一个编程问题,现在我只考虑for循环或foreach循环,如何考虑LINQ操作符。我在读C#4.0简而言之,除了练习什么建议?

    3 回复  |  直到 14 年前
        1
  •  3
  •   Amy B    14 年前

    从代码开始:

    int[] ar1=ar.Take(k-1).Reverse().ToArray(); 
    int[] ar2=ar.Skip(k - 1).Take(ar.Length - k+1).Reverse().ToArray(); 
    int[] ar3 = ar1.Concat(ar2).Reverse().ToArray(); 
    

    ar1和ar2只是枚举的,所以它们不需要是数组。不需要ToArray电话。通过一些创造性的更名,我们有:

    IEnumerable<int> revFirst = ar.Take(k-1).Reverse(); 
    IEnumerable<int> revLast = ar.Skip(k-1).Reverse(); 
    int[] ar3 = revFirst.Concat(revLast).Reverse().ToArray(); 
    

    现在我们有了

    修订(修订(第一次)+修订(最后一次))

    分配外部转速

    rev(rev(last))+rev(rev(first))

    last + first
    

    对代码应用相同的操作

    IEnumerable<int> first = ar.Take(k-1); 
    IEnumerable<int> last = ar.Skip(k-1); 
    int[] ar3 = last.Concat(first).ToArray(); 
    

    进一步简化为

    int[] ar3 = ar.Skip(k-1).Concat(ar.Take(k-1)).ToArray(); 
    

    现在我们得到了乔恩·斯凯特的答案,所以我们必须完成。

        2
  •  14
  •   Jon Skeet    14 年前

    老实说,我不知道你为什么会有这些反面。这个怎么样:

    int[] Rotate(int[] ar,int k)
    {
        if (k <= 0 || k > ar.Length - 1)
            return ar;
        return ar.Skip(k)            // Start with the last elements
                 .Concat(ar.Take(k)) // Then the first elements
                 .ToArray();         // Then make it an array
    }
    

    using System;
    using System.Linq;
    
    class Test
    {
        static int[] Rotate(int[] ar,int k)
        {
            if (k <= 0 || k > ar.Length - 1)
                return ar;
            return ar.Skip(k)            // Start with the last elements
                     .Concat(ar.Take(k)) // Then the first elements
                     .ToArray();         // Then make it an array
        }
    
        static void Main()
        {
            int[] values = { 1, 2, 3, 4, 5 };
            int[] rotated = Rotate(values, 3);
    
            Console.WriteLine(string.Join(", ", rotated));
        }
    }
    

    输出:4、5、1、2、3

    编辑:我刚刚注意到我的代码和你的原始代码之间的一个主要区别:你的修改了原始数组-我的返回一个 新的

    LINQ通常是这样设计的——它倾向于返回一个新的序列而不是修改一个现有的序列。

        3
  •  -1
  •   Mohammad Hossein Amri    6 年前

    这是我的解决方案

    public int[] solution(int[] A, int K) {
            // write your code in C# 6.0 with .NET 4.5 (Mono)
            if (A.Length <= 1)
            {
                return A;
            }
            var rotate = K % A.Length;
    
            var leftSide = A.Length - rotate;
            var arr1 = A.AsParallel().Skip(leftSide).Take(rotate);
            var arr2 = A.AsParallel().Take(leftSide);
    
            return arr1.Concat(arr2).ToArray();
    }
    

    你可以查我的电话号码 github