Возьмите первые пять элементов и последние пять элементов из массива одним запросом, используя 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);
Можно ли просто взять первые пять элементов и последние пять элементов по одному запросу?
Ответы
Ответ 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));