使用C#中的LINQ从列表中选择不同的值

我有一个Employee的集合

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 

我需要让员工具有明确的价值观empLoc,empPL,empShift。

有没有办法用LINQ实现这个目标?

您可以实现自定义IEqualityComparer

 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 { 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; } } } } 

现在你可以使用Enumerable.Distinct这个重载:

 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(); 

您可以将GroupBy匿名类型一起使用,然后获取First

 list.GroupBy(e => new { empLoc = e.empLoc, empPL = e.empPL, empShift = e.empShift }) .Select(g => g.First()); 

您可以尝试使用此代码

 var result = (from item in List select new { EmpLoc = item.empLoc, EmpPL= item.empPL, EmpShift= item.empShift }) .ToList() .Distinct(); 

我很好奇哪种方法会更快:

  1. 使用Distinct与自定义IEqualityComparer或
  2. 使用Cuong Le描述的GroupBy方法。

我发现,根据输入数据的大小和组的数量,Distinct方法可以提高性能。 (因为组的数量倾向于列表中的元素数量,不同的运行速度更快)。

代码在LinqPad中运行!

  void Main() { List cs = new List(); 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 cs) { Stopwatch sw = Stopwatch.StartNew(); sw.Restart(); var groupedCount = cs.GroupBy (o => oJ).Select(s => s.First()).Count(); groupedCount.Dump("num groups"); sw.ElapsedMilliseconds.Dump("elapsed time for using grouping"); } public void TestDistinct(List 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 { public bool Equals(C x, C y) { return xJEquals(yJ); } public int GetHashCode(C obj) { return obj.J.GetHashCode(); } } 

尝试,

 var newList = ( from x in empCollection select new {Loc = x.empLoc, PL = x.empPL, Shift = x.empShift} ).Distinct();