Я решаю эту проблему вращения массива и получаю алгоритм и код, работающие
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;
}
Это хорошо известный алгоритм программирования Pearls - 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, если мне задали проблемы с программированием, сейчас я только задумываюсь о циклах или циклах foreach, о том, как думать в терминах операторов linq. Я читаю С# 4.0 nutshell, кроме практики каких-либо советов?
Начиная с вашего кода:
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();
Поскольку вы просто хотите получить все остальные элементы, Take во второй строке не требуется.
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 (first) + 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();
и теперь у нас есть ответ Джона Скита, поэтому мы должны быть сделаны.
Я не уверен, почему у вас есть все развороты, если честно. Как насчет этого:
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
EDIT: Я только заметил одно существенное различие между моим кодом и вашим оригиналом: ваш изменяет исходный массив - my возвращает новый массив с повернутыми значениями. Так будет и ваш код LINQ, но это означает, что если вы тестировали мой код с чем-то, что только смотрело на исходный массив, вы бы не увидели поворот.
LINQ предназначен для работы таким образом в целом - он способствует возврату новой последовательности для изменения существующего.
from ...