2010-09-03 63 views
2

我解决旋转阵列的这个问题旋转阵列并得到了算法和代码工作使用LINQ语法

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简而言之,除了练习任何建议吗?

+0

这是*扩展方法*语法。 LINQ语法将从'from ...'开始。 – 2010-09-03 23:18:36

+0

是的,但是使用LINQ来指代lambda/Enumerable ...我担心这个猫已经很好用了。 :( – 2010-09-03 23:19:29

+2

@Marcelo Cantos,你指的是* query comprehension语法*。没有“LINQ语法”这样的东西。 – 2010-09-03 23:37:21

回答

3

与您的代码开始:

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(第一)+ REV(最后))

分配外转给

REV(REV(最近))+ REV(REV(第一))

其是相同

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

,现在我们有乔恩斯基特的答案,所以我们必须做到的。

+0

我爱你,当你的答案与Jon的匹配时,你知道你已经完成了。 – RichK 2010-09-04 14:33:28

+0

精彩的解释!谢谢你回答我的答案和乔恩的回答,并从我的出发,努力! – satyajit 2010-09-04 19:49:25

13

我不确定为什么你有所有的逆转,说实话。这个怎么样:

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代码也是如此,但这意味着如果你用我们的代码测试了一些只能看到原始数组的代码,你就看不到旋转。

LINQ被设计成通用这种方式 - 它有利于返回一个新的序列而不是修改现有的序列。

+0

这不是为我旋转数组,它只是返回原始数组。在IDE中检查 – satyajit 2010-09-03 23:33:50

+0

@satyajit:然后你没有正确地使用它,我将添加一个简短但完整的程序来显示它的工作 – 2010-09-04 08:37:34

+0

是的,我现在明白你的代码正在返回一个新的数组。向我解释! – satyajit 2010-09-04 19:47:41