C# 在C中使用LINQ从列表中选择不同的值
我收集了一批雇员C# 在C中使用LINQ从列表中选择不同的值,c#,.net,linq,C#,.net,Linq,我收集了一批雇员 Class Employee { empName empID empLoc empPL empShift } 我的名单上有 empName,empID,empLoc,empPL,empShift E1,1,L1,EPL1,S1 E2,2,L2,EPL2,S2 E3,3,L3,EPL3,S3 E4,4,L1,EPL1,S1 E5,5,L5,EPL5,S5 E6,6,L2,EPL2,S2 我需要
Class Employee
{
empName
empID
empLoc
empPL
empShift
}
我的名单上有
empName,empID,empLoc,empPL,empShift
E1,1,L1,EPL1,S1
E2,2,L2,EPL2,S2
E3,3,L3,EPL3,S3
E4,4,L1,EPL1,S1
E5,5,L5,EPL5,S5
E6,6,L2,EPL2,S2
我需要考虑具有不同价值观的员工
empoc,empPL,empShift
使用LINQ有什么方法可以实现这一点吗?您可以尝试使用此代码
var result = (from item in List
select new
{
EmpLoc = item.empLoc,
EmpPL= item.empPL,
EmpShift= item.empShift
})
.ToList()
.Distinct();
试试看
您可以将GroupBy与匿名类型一起使用,然后首先获取:
您可以实现一个自定义: 使用匿名类型的可重用性、健壮性和效率较低的方法:
var distinctKeys = employees.Select(e => new { e.empLoc, e.empPL, e.empShift })
.Distinct();
var joined = from e in employees
join d in distinctKeys
on new { e.empLoc, e.empPL, e.empShift } equals d
select e;
// if you want to replace the original collection
employees = joined.ToList();
我很好奇哪种方法更快: 与自定义IEqualityComparer一起使用Distinct,或 使用Cuong Le描述的GroupBy方法。 我发现,根据输入数据的大小和组的数量,Distinct方法的性能要高得多。当组的数量趋向于列表中元素的数量时,distinct运行得更快 代码在LinqPad中运行
void Main()
{
List<C> cs = new List<C>();
foreach(var i in Enumerable.Range(0,Int16.MaxValue*1000))
{
int modValue = Int16.MaxValue; //vary this value to see how the size of groups changes performance characteristics. Try 1, 5, 10, and very large numbers
int j = i%modValue;
cs.Add(new C{I = i, J = j});
}
cs.Count ().Dump("Size of input array");
TestGrouping(cs);
TestDistinct(cs);
}
public void TestGrouping(List<C> cs)
{
Stopwatch sw = Stopwatch.StartNew();
sw.Restart();
var groupedCount = cs.GroupBy (o => o.J).Select(s => s.First()).Count();
groupedCount.Dump("num groups");
sw.ElapsedMilliseconds.Dump("elapsed time for using grouping");
}
public void TestDistinct(List<C> cs)
{
Stopwatch sw = Stopwatch.StartNew();
var distinctCount = cs.Distinct(new CComparerOnJ()).Count ();
distinctCount.Dump("num distinct");
sw.ElapsedMilliseconds.Dump("elapsed time for using distinct");
}
public class C
{
public int I {get; set;}
public int J {get; set;}
}
public class CComparerOnJ : IEqualityComparer<C>
{
public bool Equals(C x, C y)
{
return x.J.Equals(y.J);
}
public int GetHashCode(C obj)
{
return obj.J.GetHashCode();
}
}
您需要这些员工的全部信息,还是只需要empLoc、Empll和Emplit?顺便说一句,您的命名非常糟糕-鉴于它们在Employee类中,emp前缀是多余的,但Loc和PL本身就相对没有意义。@JonSkeet这是基本要求。我刚上了一节课。但在原始版本中,它有很多属性,我只需要检查3个属性。对此我很抱歉:。我需要全部信息。不只是empLoc、empPL和empShift。你能用复合密钥匿名类型与morelinq进行区分吗?Tim我用IEqualityComparer试过了,它对我很有效。但是,您提供的第二个解决方案工作不正常。独特查询不起作用。它包含一个包含empLoc、empPl、empShift的列表,并且连接也未按预期工作。你能看一下吗?Thanks@VeeKeyBee:第二种解决方案类似于Aghilas方法。将键字段选择为匿名类型,然后使用Enumerable.Distinct。但是,我没有选择匿名类型,而是将其与原始员工集合合并,注意末尾的select e。这应该也行,这就是我们所说的完整解决方案。尽管我必须说,@congule用一个非常有价值的短发回答了这个问题@好奇:GroupBy aproach很好。但这比为CPU和内存使用定制的IEQualityComparerf要复杂得多。对于大多数LINQ扩展方法,可以重用IEqualityComparer。如果实现会改变,你只有一个地方需要修复。@TimSchmelter:你是对的。因为我需要临时工,所以我会采用分组方式。如果比较器要重复使用,我肯定会接受你的建议:这是最方便的方法!除非我能再投票10次:哪一个更有效率?GroupBy可能会慢很多,这取决于组的数量。如果组计数接近输入数组的大小,且输入数组的大小较大,则应采用不同的方法。见下面我的答案
public class Employee
{
public string empName { get; set; }
public string empID { get; set; }
public string empLoc { get; set; }
public string empPL { get; set; }
public string empShift { get; set; }
public class Comparer : IEqualityComparer<Employee>
{
public bool Equals(Employee x, Employee y)
{
return x.empLoc == y.empLoc
&& x.empPL == y.empPL
&& x.empShift == y.empShift;
}
public int GetHashCode(Employee obj)
{
unchecked // overflow is fine
{
int hash = 17;
hash = hash * 23 + (obj.empLoc ?? "").GetHashCode();
hash = hash * 23 + (obj.empPL ?? "").GetHashCode();
hash = hash * 23 + (obj.empShift ?? "").GetHashCode();
return hash;
}
}
}
}
var distinct = employees.Distinct(new Employee.Comparer());
var distinctKeys = employees.Select(e => new { e.empLoc, e.empPL, e.empShift })
.Distinct();
var joined = from e in employees
join d in distinctKeys
on new { e.empLoc, e.empPL, e.empShift } equals d
select e;
// if you want to replace the original collection
employees = joined.ToList();
void Main()
{
List<C> cs = new List<C>();
foreach(var i in Enumerable.Range(0,Int16.MaxValue*1000))
{
int modValue = Int16.MaxValue; //vary this value to see how the size of groups changes performance characteristics. Try 1, 5, 10, and very large numbers
int j = i%modValue;
cs.Add(new C{I = i, J = j});
}
cs.Count ().Dump("Size of input array");
TestGrouping(cs);
TestDistinct(cs);
}
public void TestGrouping(List<C> cs)
{
Stopwatch sw = Stopwatch.StartNew();
sw.Restart();
var groupedCount = cs.GroupBy (o => o.J).Select(s => s.First()).Count();
groupedCount.Dump("num groups");
sw.ElapsedMilliseconds.Dump("elapsed time for using grouping");
}
public void TestDistinct(List<C> cs)
{
Stopwatch sw = Stopwatch.StartNew();
var distinctCount = cs.Distinct(new CComparerOnJ()).Count ();
distinctCount.Dump("num distinct");
sw.ElapsedMilliseconds.Dump("elapsed time for using distinct");
}
public class C
{
public int I {get; set;}
public int J {get; set;}
}
public class CComparerOnJ : IEqualityComparer<C>
{
public bool Equals(C x, C y)
{
return x.J.Equals(y.J);
}
public int GetHashCode(C obj)
{
return obj.J.GetHashCode();
}
}