仅基于表的一个字段在 Linq 中区分

Posted

技术标签:

【中文标题】仅基于表的一个字段在 Linq 中区分【英文标题】:Distinct in Linq based on only one field of the table 【发布时间】:2013-01-14 15:07:22 【问题描述】:

我正在尝试在 Linq 中使用 .distinct 根据表的一个字段获取结果(因此不需要表中的整个重复记录)。

我知道使用 distinct 编写基本查询,如下所示:

var query = (from r in table1
orderby r.Text
select r).distinct();

但我需要r.text 不重复的结果。

【问题讨论】:

您需要指定要区分的字段,请参阅msdn.microsoft.com/en-us/library/bb348436.aspx 【参考方案1】:

试试这个:

table1.GroupBy(x => x.Text).Select(x => x.FirstOrDefault());

这将按Text 对表进行分组,并使用每个组中的第一行,从而得到Text 不同的行。

【讨论】:

如果 groupby 有多个字段怎么办? @user585440:在这种情况下,您使用匿名类型,如下所示:table1.GroupBy(x => new x.Text, x.Property2, x.Property3 ).Select(x => x.First()); 是的,你是对的,我已经找到了。不管怎么说,还是要谢谢你。而且我还发现 Select(x => x.First()) 会导致崩溃。最好改成Select(x => x.FirstOrDefault()); 我必须使用 FirstOrDefault 否则会出现运行时错误 @TruthOf42 这不太可能。 GroupBy 不会创建空组,请参阅我之前的评论。很可能,您的代码包含的内容比您在此处看到的要多。也许您也有WhereFirst 的条件。【参考方案2】:

MoreLinq 有一个您可以使用的DistinctBy 方法:

它将允许您这样做:

var results = table1.DistictBy(row => row.Text);

方法的实现(缺少参数验证)如下:

private static IEnumerable<TSource> DistinctByImpl<TSource, TKey>(IEnumerable<TSource> source,
    Func<TSource, TKey> keySelector, IEqualityComparer<TKey> comparer)

    HashSet<TKey> knownKeys = new HashSet<TKey>(comparer);
    foreach (TSource element in source)
    
        if (knownKeys.Add(keySelector(element)))
        
            yield return element;
        
    

【讨论】:

对不起,我不热衷于使用equalComparer。 @MeghaJain 好吧,无论如何都会使用一个,因为GroupBy 也需要一个。如果没有提供,这两种方法都将使用默认的EqualityComparer 好吧,如果我错了,请纠正我,但是这里的区别是在内存中完成的,而不是在 DB 中?这不会导致不需要的全扫描吗? @Kek。不,由于收益回报,您将停在第一个不同的元素。最终,是的,您会将每个键加载到 HashSet 中,但由于它是 IEnumerable in 和 IEnumerable out,因此您只会得到这些项目。如果您在谈论 LINQ to SQL,那么是的,这将执行表扫描。【参考方案3】:

但我需要不重复 r.text 的结果

听起来好像你想要这个:

table1.GroupBy(x => x.Text)
      .Where(g => g.Count() == 1)
      .Select(g => g.First());

这将选择Text 唯一的行。

【讨论】:

【参考方案4】:

Daniel Hilgarth 上面的回答导致System.NotSupported 出现Entity-Framework 异常。对于 Entity-Framework,它必须是:

table1.GroupBy(x => x.Text).Select(x => x.FirstOrDefault());

【讨论】:

【参考方案5】:

围绕这个话题有很多讨论。

你可以找到其中一个here:

最流行的建议之一是 @Servy 指出的将 lambda 表达式作为参数的 Distinct 方法。

C# 的首席架构师 Anders Hejlsberg 提出了解决方案 here。还解释了为什么框架设计团队决定不添加采用 lambda 的 Distinct 方法的重载。

【讨论】:

【参考方案6】:

根据我的发现,您的查询大部分是正确的。只需将“select r”更改为“select r.Text”即可,这应该可以解决问题。这就是 MSDN 记录它应该如何工作的方式。

例如:

    var query = (from r in table1 orderby r.Text select r.Text).distinct();

【讨论】:

您更改了在这种情况下可能不需要的“select”语句【参考方案7】:
data.Select(x=>x.Name).Distinct().Select(x => new SelectListItem  Text = x );

【讨论】:

这没有回答问题。【参考方案8】:

如果你的情况是这样的话,那就给你单独返回一个列!

CountryData.Select(x=>x.COUNTRY_NAME).Distinct()

如果您需要由一列不同的多列。您需要先groupby,然后从组中选择第一项。 (在这种情况下,不会返回组中具有不同值的其余项目)

CountryData.GroupBy(a=>a.COUNTRY_NAME).Select(a=>a.First());

【讨论】:

【参考方案9】:

试试这个代码:

table1.GroupBy(x => x.Text).Select(x => x.FirstOrDefault());

【讨论】:

【参考方案10】:

你可以试试这个:table1.GroupBy(t =&gt; t.Text).Select(shape =&gt; shape.r)).Distinct();

【讨论】:

以上是关于仅基于表的一个字段在 Linq 中区分的主要内容,如果未能解决你的问题,请参考以下文章

如何使用LINQ返回多个自选字段

当涉及两个以上的表时,如何将来自相似字段的单个表的两个左连接转换为 LINQ? [复制]

Linq查询连接guid与varchar字段

使用 Linq 反对,我怎样才能获得基于同一列表中另一个字段的值

在实践中区分 HTTP 状态码 403 和 409(或 400)

Linq to Sql 左连接 , 取右表可能为 null的 int类型字段