【问题标题】:I need to get multiple index's instead of one using linq我需要使用 linq 获取多个索引而不是一个
【发布时间】:2019-10-11 17:09:39
【问题描述】:

这应该很简单,但我搜索并找不到类似的 linq 示例。

下面有一个函数。

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

它返回销售列表中的索引。

我需要对其进行自定义以返回多个硬编码索引,例如 1、3、4、6。

如何使用 linq 在一行中执行此操作?

非常感谢!

【问题讨论】:

  • SLGDeptSalesList 是什么?你想从中提取什么?
  • 我想我需要一个和某处。所以这将返回索引 0。我需要索引 1、2、3 和 5。
  • 您的意思是您需要索引 1、2、3 和 5 处的值?
  • 是索引处的那些值。嘿大家感谢所有的答案。它们都工作得很好。
  • 在找不到索引时是否需要异常,还是应该返回正常的元素?

标签: c# .net list linq


【解决方案1】:

您可以在数组上使用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/

【讨论】:

  • 效果很好。谢谢!
  • 请注意 Contains 是 O(n),这意味着当在 Where 中使用时,整个查询变为 O(n^2)。
  • @Sweeper 通常它不是 O(n),例如Hashset.Contains。即使对于一个数组,它也永远不会是 O(n^2),它会是 O(n*m),而且我们已经知道 m 是“硬编码”的,因此远非无限。
  • @IanMercer 我承认这是真的,但 IMO 这仍然是个坏习惯。 这次数组是硬编码的,下次呢?我并不是说这本质上是不好的。对不起,如果我用错了词。
  • @Sweeper thx,两个答案都很好。选择取决于缺少索引时的可读性和所需行为,以及是否需要在 value 上添加任何其他条件,以及此查询是否需要移动以在 SQL 中而不是在本地执行。
【解决方案2】:

您可以在硬编码的索引列表上执行Select,将它们转换为viewModel.SLGDeptSalesList 列表中的相应元素:

viewModel.SLGDeptSalesList = new List<int> { 1, 3, 4, 6 }.Select(x => viewModel.SLGDeptSalesList[x]).ToList();

【讨论】:

    【解决方案3】:

    如果您的索引在列表中被硬编码,那么您可以在 Where 中使用 .Exists()。但如果他们只是

       var indices = new List<int>(){1,3,4,6};
       viewModel.SLGDeptSalesList = viewModel.SLGDeptSalesList.Where((value, index) => indices.Exists(index)).ToList();
    

    【讨论】:

      【解决方案4】:

      已经有内置的 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]);
      }
      

      【讨论】:

      • 西奥多的东西太刺激了!你知识渊博!谢谢!
      • 我的荣幸 JSkyS! :-)
      猜你喜欢
      • 2021-11-03
      • 1970-01-01
      • 1970-01-01
      • 2019-12-23
      • 2016-05-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多