【问题标题】:LINQ query for finding one item in list AND verifying list does not contain another item用于在列表中查找一项并验证列表不包含另一项的 LINQ 查询
【发布时间】:2016-03-03 22:24:13
【问题描述】:

到目前为止,我想出了这个:

list.Any(s => s.EnumIdValue == Close) && !list.Any(s => s.EnumIdValue == Reset || s.EnumIdValue == Cancel);

EnumIdValue 包含几个不同的可能值,如 Close、Reset、Cancel、SomeOtherState 等。不应该有重复,但它仍然是可能的。

这正是我想要的。但是有没有更好(更短)的方式来编写这个查询?

【问题讨论】:

  • 应该有一些徽章来写一个看起来很简单的问题,并且得到多个不正确的猜测答案。
  • CoderDennis:这不是我的本意,但你说得对,我想我应该这样做。 :P
  • 答案不正确,因为该问题具有误导性。事实上,我什至没有看到任何问题。

标签: c# linq


【解决方案1】:

您的原件很好。另一个可行的变体是这样的:

var newQuery =
    list.Any(s => s.EnumIdValue == EnumIdValue.Close) &&
    list.All(s => s.EnumIdValue != EnumIdValue.Reset &&
                  s.EnumIdValue != EnumIdValue.Cancel);

英文:列表中是否至少有一个Close并且列表中的每一项都不是Reset,也不是Cancel

顺便说一句,有时对代码进行很好的格式化会在可读性方面产生很大的影响。

【讨论】:

    【解决方案2】:

    答案是:没有更好的写法了。

    如果您尝试将其写在一个 lambda 中,您可以将 s 视为列表中的单个项目。如果该项目是Close,它当然不会是别的东西,所以在同一个 lambda 中检查它是没有用的。如果要检查列表是否不包含其他值,则必须使用另一个表达式。

    【讨论】:

      【解决方案3】:

      您可以使用HashSet 来测试集合是否包含每个EnumIdValue 中的至少1 个

      var enumIds = list.Select(s => s.EnumIdValue).ToHashSet();
      
      return enumIds.Contains(Close) && !(enumIds.Contains(Cancel) || enumIds.Contains(Reset));
      
      // or
      
      return enumIds
        .Intersect(new[] { Cancel, Reset, Close })
        .SequenceEqual(new [] { Close });
      
      // or (throws exception)
      
      enumIds.IntersectWith(new[] { Cancel, Reset, Close })
      return enumIds.Single() == Close;
      

      如果您需要根据enumIds 是否包含Close 进行不同类型的检查,这将非常有用。

      【讨论】:

      • IntersectsWith 或只是Intersect?
      • @devuxer:现在让我们坚持使用IntersectWith。我确实有错误的返回值。
      • 我问是因为IntersectWith(或IntersectsWith)在本机LINQ中不存在:msdn.microsoft.com/en-us/library/bb546153.aspx
      • 没关系。我看到这是HashSet的实际方法。
      • 在这种情况下,转换为HasSet 似乎是不必要的,但您可以将其保留为IEnumerable 并使用Intersect。您也许可以为性能提出理由,但我认为这是过早的优化,而且我不会自动假设ToHashSet 可以节省时间(取决于Intersect 的内部实现)。尽管如此,有趣的答案:)
      【解决方案4】:

      怎么样

          var items = list.Select(s => s.EnumIdValue == Close) 
          if(items.Count==1)
          {
             //todo
          }
      

      【讨论】:

      • 那只解决了一半的问题,甚至不是很好
      • 如果它包含 3 个 Close 副本怎么办?
      【解决方案5】:

      这是一个相当易读的替代方案:

      var opts = new [] { Close, Reset, Cancel };
      var desired = new [] { Close };
      return list
              .Select(s => s.EnumIdValue)
              .Distinct()
              .Where(opts.Contains)
              .SequenceEqual(desired);
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2012-07-10
        • 1970-01-01
        • 2017-06-06
        • 2018-03-13
        • 2017-12-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多