尝试将Distinct()放入一个相对复杂的LINQ查询中

本文关键字:复杂 相对 LINQ 一个 查询 Distinct | 更新日期: 2023-09-27 17:52:42

到目前为止,我有这个查询:

 var msg = ModelState.Values
                   .Where(x => x.Errors.Any())
                   .Select(c => c.Errors.Select(d => d.ErrorMessage).Aggregate((e, f) => (e ?? "") + "<br/>" + f))
                   .Aggregate((x, y) => (x ?? "") + "<br/>" + y);

这是完美的工作,但我需要过滤掉重复的错误消息。我尝试将GroupBy()和Distinct()添加到获取ErrorMessage的谓词之前和之后的几个地方。我错过了什么?

如果我按原样运行,我将收到以下结果:

"Contact Email address invalid<br/>Contact Email address invalid"

这里的每个ErrorMessage值都是"Contact Email address invalid"。这些是我想要过滤掉的重复内容。

尝试将Distinct()放入一个相对复杂的LINQ查询中

我可以建议一个替代方案吗?

假设您想要不同的消息,由break标签分隔:

var items = ModelState.Values
    .SelectMany(c => c.Errors.Select(d => d.ErrorMessage))
    .Distinct()
    .ToArray();
string msg = string.Join("<br/>", items);

问题是您有两个地方产生值。考虑以下情况:

Value   Errors
1.      "Bad username", "Contact Email address invalid"
2.      "Contact Email address invalid"

即使您将Distinct添加到两个Select调用中,它也不会做您想要的,因为Bad username<br/>Contact Email address invalid将与Contact Email address invalid进行比较,将发现不相等,并将聚合到Bad username<br/>Contact Email address invalid<br/>Contact Email address invalid中,我认为这不是您想要的。

相反,您应该首先平坦化嵌套的错误列表。这是SelectMany的工作。要使列表平整化,你只需要这样做:

var errorMessages = ModelState.Values
               .Where(x => x.Errors.Any())
               .SelectMany(c => c.Errors.Select(d => d.ErrorMessage))

现在errorMessages是来自每个Value每个错误消息的列表。(注意Where 可能不需要: SelectSelectMany在空序列上是no-op。)

现在是第二个问题:

由于string的不可变性,在c#中对字符串使用+几乎总是不好的做法。相反,您希望使用string.Joinstring.FormatStringBuilder,这取决于您的输入是一个序列、多个变量还是更长的字符串。在本例中,您有一个数组,因此string.Join是选择的工具:
var msg = string.Join("<br/>", errorMessages.Distinct())