LINQ查询:查找列表中的一个项目并验证该列表不包含另一个项目

4
到目前为止,我已经想出了这个方案:
list.Any(s => s.EnumIdValue == Close) && !list.Any(s => s.EnumIdValue == Reset || s.EnumIdValue == Cancel);

EnumIdValue包含多个不同的可能值,例如Close、Reset、Cancel、SomeOtherState等。不应该有重复,但仍然有可能出现。

这段代码正好符合我的要求。但是否有更好(更短)的方法来编写此查询?


应该为那些提出看似简单却得到多个错误猜测答案的问题的人提供一些徽章。 - CoderDennis
CoderDennis:这不是我的意图,但你说得对,我想我应该这样做。 :P - Andrew
答案不正确是因为问题具有误导性。事实上,我甚至看不到一个问题。 - Jonathan Allen
5个回答

4
你的原文没问题。另一个可行的变体是这样的:
var newQuery =
    list.Any(s => s.EnumIdValue == EnumIdValue.Close) &&
    list.All(s => s.EnumIdValue != EnumIdValue.Reset &&
                  s.EnumIdValue != EnumIdValue.Cancel);

这句话的意思是:列表中是否至少有一个“Close”,并且列表中的每个项目都不是“Reset”或“Cancel”?另外,有时精美地格式化代码会大大提高可读性。

3
答案是:没有更好的方法来写它。 如果你试图在一个lambda中写它,你可以把s看作列表中的一个单独项。如果这个项是一个Close,那么它当然不会是其他东西,所以在同一个lambda中检查它是无用的。如果你想检查列表中是否不包含其他值,你必须使用另一个表达式来实现。

1

您可以使用 HashSet 来测试集合是否包含 至少一个 EnumIdValue

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
@devuxer:现在让我们继续使用IntersectWith。我之前的返回值是错误的。 - Jacob Krall
我之所以问是因为IntersectWith(或IntersectsWith)在本地LINQ中不存在: https://msdn.microsoft.com/en-us/library/bb546153.aspx - devuxer
没关系,我看到这实际上是 HashSet 的一个方法。 - devuxer
在这种情况下,似乎将其转换为HasSet是不必要的,您可以将其保留为IEnumerable并使用Intersect。您可能会为性能辩护,但我认为这是过早的优化,并且我不会自动假设ToHashSet会节省时间(这取决于Intersect的内部实现)。尽管如此,这是一个有趣的答案 :) - devuxer
@devuxer:是的,当.Count() != 1时,.Single()会抛出异常。我发了另一个使用IntersectSequenceEqual的例子。这给了我一个更好的答案的想法。 - Jacob Krall

0

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

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

0

怎么样?

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

那只回答了问题的一半,而且还不是很好。 - CoderDennis
如果它包含3个Close的副本,会怎么样? - Jonathan Allen

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接