仅基于表的一个字段在 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
不会创建空组,请参阅我之前的评论。很可能,您的代码包含的内容比您在此处看到的要多。也许您也有Where
或First
的条件。【参考方案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 => t.Text).Select(shape => shape.r)).Distinct();
【讨论】:
以上是关于仅基于表的一个字段在 Linq 中区分的主要内容,如果未能解决你的问题,请参考以下文章
当涉及两个以上的表时,如何将来自相似字段的单个表的两个左连接转换为 LINQ? [复制]
使用 Linq 反对,我怎样才能获得基于同一列表中另一个字段的值