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

时间:2016-06-28 19:48:11

标签: c# linq

到目前为止我有这个问题:

 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值都是“联系电子邮件地址无效”。这些是我想要过滤的副本。

2 个答案:

答案 0 :(得分:2)

我可以提出替代方案吗?

假设您需要以break标记分隔的不同消息:

var items = ModelState.Values
    .SelectMany(c => c.Errors.Select(d => d.ErrorMessage))
    .Distinct()
    .ToArray();

string msg = string.Join("<br/>", items);

答案 1 :(得分:2)

问题在于你有两个地方产生价值。考虑以下情况:

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进行比较,发现不相等,并将汇总到var errorMessages = ModelState.Values .Where(x => x.Errors.Any()) .SelectMany(c => c.Errors.Select(d => d.ErrorMessage)) ,我认为这不是你想要的。

相反,您应该首先展平嵌套的错误列表。这是SelectMany的工作。要展平您的列表,您只需要:

errorMessages

现在Value是来自每个Where每条错误消息的列表。 (请注意,Select 可能不需要:空序列中的SelectMany+是无操作。)

现在有第二个问题:

由于string的不可变性,在C#中使用string.Join字符串几乎总是不好的做法。相反,您要使用string.Joinstring.FormatStringBuilder,具体取决于您的输入是序列,多个变量还是更长的字符串。在这种情况下,您有一个数组,因此var msg = string.Join("<br/>", errorMessages.Distinct()) 是首选工具:

# open connection to ec2
conn = get_ec2_conn()
# get a list of all instances
all_instances = conn.get_all_instances()
# get instances with filter of running + with tag `Name`
instances = conn.get_all_instances(filters={'tag-key': 'Name', 'instance-state-name': 'running'})
# make a list of filtered instances IDs `[i.id for i in instances]`
# Filter from all instances the instance that are not in the filtered list
instances_to_delete = [to_del for to_del in all_instances if to_del.id not in [i.id for i in instances]]
# run over your `instances_to_delete` list and terminate each one of them
for instance in instances_to_delete:
    conn.stop_instances(instance.id)