Подтвердить что ты не робот

Возьмите первые пять элементов и последние пять элементов из массива одним запросом, используя LINQ

Недавно меня спросил сотрудник: возможно ли взять первые пять элементов и последние пять элементов по одному запросу из массива?

int[] someArray = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18 };

Что я пробовал:

int[] someArray = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18 };
var firstFiveResults = someArray.Take(5);
var lastFiveResults = someArray.Skip(someArray.Count() - 5).Take(5);
var result = firstFiveResults;
result = result.Concat(lastFiveResults);

Можно ли просто взять первые пять элементов и последние пять элементов по одному запросу?

4b9b3361

Ответ 1

Вы можете использовать метод .Where с лямбда, который принимает индекс элемента как свой второй параметр:

int[] someArray = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18 };

int[] newArray = someArray.Where((e, i) => i < 5 || i > someArray.Length - 6).ToArray();

foreach (var item in newArray) Console.WriteLine(item);

Вывод:

0, 1, 2, 3, 4, 14, 15, 16, 17, 18

Ответ 2

Решение с ArraySegment<> (требуется .NET 4.5 (2012) или новее):

var result = new ArraySegment<int>(someArray, 0, 5)
  .Concat(new ArraySegment<int>(someArray, someArray.Length - 5, 5));

И решение с Enumerable.Range:

var result = Enumerable.Range(0, 5).Concat(Enumerable.Range(someArray.Length - 5, 5))
  .Select(idx => someArray[idx]);

Оба этих решения избегают повторения через "средний" массив (индексы с 5 по 13).

Ответ 3

Если вы не играете головоломки кода со своими коллегами, но просто хотите создать новый массив с вашими критериями, я бы не сделал этого с запросами вообще, но использовал Array.copy.

Можно рассмотреть три различных случая:

  • исходный массив имеет менее 5 элементов
  • исходный массив имеет от 5 до 9 элементов
  • исходный массив имеет 10 или более элементов

Третий - это простой случай, так как первый и последний 5 элементов различны и четко определены.

Остальные два требуют больше размышлений. Я собираюсь предположить, что вы хотите следующее, проверьте эти предположения:

Если исходный массив имеет менее 5 элементов, вам понадобится массив из элементов 2 * (длина массива), например [1, 2, 3] станет [1, 2, 3, 1, 2, 3]

Если исходный массив имеет от 5 до 9 элементов, вам нужно иметь массив из примерно 10 элементов, например [1, 2, 3, 4, 5, 6] становится [1, 2, 3, 4, 5, 2, 3, 4, 5, 6]

Демонстрационная программа

public static void Main()
{
    Console.WriteLine(String.Join(", ", headandtail(new int[]{1, 2, 3})));
    Console.WriteLine(String.Join(", ", headandtail(new int[]{1, 2, 3, 4, 5, 6})));
    Console.WriteLine(String.Join(", ", headandtail(new int[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11})));
}

private static T[] headandtail<T>(T[] src) {
    int runlen = Math.Min(src.Length, 5);
    T[] result = new T[2 * runlen];
    Array.Copy(src, 0, result, 0, runlen);
    Array.Copy(src, src.Length - runlen, result, result.Length - runlen, runlen);
    return result;
}

которая выполняется в O (1);

Если вы играете головоломки кода с вашими коллегами, все самое интересное в головоломке, не так ли?

Это тривиально, хотя.

src.Take(5).Concat(src.Reverse().Take(5).Reverse()).ToArray();

это выполняется в O (n).

Ответ 4

Попробуйте следующее:

var result = someArray.Where((a, i) => i < 5 || i >= someArray.Length - 5);

Ответ 5

Это должно работать

someArray.Take(5).Concat(someArray.Skip(someArray.Count() - 5)).Take(5);

Ответ 6

Попробуйте следующее:

int[] someArray = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18 };
var firstFiveResults = someArray.Take(5);
var lastFiveResults = someArray.Reverse().Take(5).Reverse();
var result = firstFiveResults;
result = result.Concat(lastFiveResults);

Второй Reverse() переупорядочивает номера, поэтому вы не получите 18,17,16,15,14

Ответ 7

Пожалуйста, попробуйте следующее:

var result = someArray.Take(5).Union(someArray.Skip(someArray.Count() - 5).Take(5));