Поворот массива с использованием синтаксиса LINQ

2

Я решаю эту проблему вращения массива и получаю алгоритм и код, работающие

 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, кроме практики каких-либо советов?

  • 0
    Это синтаксис метода расширения . Синтаксис LINQ будет начинаться с from ...
  • 0
    Да, но используя LINQ для обозначения лямбд / перечислимых ... Я боюсь, что кошка не в порядке. :(
Показать ещё 3 комментария
Теги:
linq
arrays
rotation

2 ответа

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

Поскольку вы просто хотите получить все остальные элементы, 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(); 

и теперь у нас есть ответ Джона Скита, поэтому мы должны быть сделаны.

  • 1
    Мне нравится, что вы знаете, что вы сделали, когда ваш ответ совпадает с ответом Джона.
  • 0
    Замечательное объяснение! Спасибо, что просмотрели мой ответ и ответ Джона и извлекли его из моего, большое усилие!
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

EDIT: Я только заметил одно существенное различие между моим кодом и вашим оригиналом: ваш изменяет исходный массив - my возвращает новый массив с повернутыми значениями. Так будет и ваш код LINQ, но это означает, что если вы тестировали мой код с чем-то, что только смотрело на исходный массив, вы бы не увидели поворот.

LINQ предназначен для работы таким образом в целом - он способствует возврату новой последовательности для изменения существующего.

  • 0
    Это не вращение массива для меня, это просто возврат исходного массива. Только что проверил в IDE.
  • 0
    @satyajit: Тогда вы не используете его должным образом. Я добавлю короткую, но полную программу, чтобы показать, как она работает.
Показать ещё 2 комментария

Ещё вопросы

Сообщество Overcoder
Наверх
Меню