Мне нужно получить несколько индексов вместо одного, используя linq - PullRequest
2 голосов
/ 11 октября 2019

Это должно быть очень просто, но я искал и не смог найти похожий пример linq.

У меня есть функция ниже.

viewModel.SLGDeptSalesList = viewModel.SLGDeptSalesList.Where(
    (value, index) => index == 0).ToList();

Возвращает индекс в списке продаж.

Мне нужно настроить его так, чтобы он возвращал несколько жестко закодированных индексов, таких как 1,3,4,6.

Как я могу использовать linq, чтобы сделать это в одну строку?

Спасибо большое!

Ответы [ 4 ]

3 голосов
/ 11 октября 2019

Вы можете использовать Contains для массива:

var indices = new [] {1, 3, 4, 6};
viewModel.SLGDeptSalesList = viewModel.SLGDeptSalesList.Where(
  (value, index) => indices.Contains(index)).ToList();

Использование Contains для массива является обычной техникой, когда у вас есть запросы, которые вы хотите выполнить на SQL (не в вашем случае, нов общем), например https://blogs.msdn.microsoft.com/alexj/2009/03/25/tip-8-how-to-write-where-in-style-queries-using-linq-to-entities/

2 голосов
/ 11 октября 2019

Вы можете сделать Select в своем жестко закодированном списке индексов, чтобы преобразовать их в соответствующие элементы в списке viewModel.SLGDeptSalesList:

viewModel.SLGDeptSalesList = new List<int> { 1, 3, 4, 6 }.Select(x => viewModel.SLGDeptSalesList[x]).ToList();
1 голос
/ 11 октября 2019

Уже существует встроенный метод 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]);
}
1 голос
/ 11 октября 2019

Если ваши индексы жестко закодированы в списке, вы можете просто использовать .Exists () в вашем Where. но если они просто

   var indices = new List<int>(){1,3,4,6};
   viewModel.SLGDeptSalesList = viewModel.SLGDeptSalesList.Where((value, index) => indices.Exists(index)).ToList();
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...