Уже существует встроенный метод LINQ ElementAt
, поэтому у нас также может быть ElementsAt
, который принимает несколько индексов.
public static IEnumerable<TSource> ElementsAt<TSource>(
this IEnumerable<TSource> source, params int[] indices)
{
var indicesHashSet = new HashSet<int>(indices);
return source.Where((x, i) => indicesHashSet.Contains(i));
}
Эта реализация возвращает элементыв порядке их нахождения в источнике и игнорирует повторяющиеся индексы.
Пример использования:
viewModel.SLGDeptSalesList =
viewModel.SLGDeptSalesList.ElementsAt(1, 3, 4, 6).ToList();
Обновление: Вот альтернативная реализация. Этот возвращает элементы в порядке индексов, а в случае дублирования индексов возвращает дубликаты элементов. В случае, если индексы находятся за пределами диапазона, исключение не выдается, но элементы для этих индексов не возвращаются. Поэтому не гарантируется, что выходная последовательность будет иметь одинаковую длину с запрошенными индексами.
public static IEnumerable<TSource> ElementsAt<TSource>(
this IEnumerable<TSource> source, params int[] indices)
{
return indices.Join(source.Select((Item, Index) => (Item, Index)),
i => i, p => p.Index, (_, p) => p.Item);
}
Обновление: А вот схоластический вариант предыдущей реализации. Это гарантирует, что запрошенные индексы и выходная последовательность будут иметь одинаковую длину. Исключение выдается для индексов за пределами исходной последовательности.
public static IEnumerable<TSource> ElementsAt<TSource>(
this IEnumerable<TSource> source, params int[] indices)
{
var indicesHashSet = new HashSet<int>(indices);
var foundElements = source.Select((Item, Index) => (Item, Index))
.Where(p => indicesHashSet.Contains(p.Index))
.ToDictionary(p => p.Index, p => p.Item);
var notFoundIndices = indices.Where(i => !foundElements.ContainsKey(i)).ToList();
if (notFoundIndices.Count > 0)
throw new ArgumentOutOfRangeException(nameof(indices),
$"Indices [{String.Join(", ", notFoundIndices)}] " +
$"are outside the bounds of the {nameof(source)} sequence.");
return indices.Select(i => foundElements[i]);
}