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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/12580360/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-09 23:46:39  来源:igfitidea点击:

Select distinct values from a list using LINQ in C#

c#.netlinq

提问by kbvishnu

I have a collection of Employee

我有一个 Employee 集合

Class Employee

{
  empName
  empID
  empLoc 
  empPL
  empShift
}

My list contains

我的清单包含

 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

I need to take the employees having distinct values empLoc,empPL,empShift.

我需要让具有不同价值观的员工 empLoc、empPL、empShift。

Is there is any way to achieve this using LINQ ?

有什么方法可以使用 LINQ 实现这一点吗?

采纳答案by Tim Schmelter

You could implement a custom IEqualityComparer<Employee>:

您可以实现自定义IEqualityComparer<Employee>

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

Now you can use this overload of Enumerable.Distinct:

现在您可以使用以下重载Enumerable.Distinct

var distinct = employees.Distinct(new Employee.Comparer());


The less reusable, robust and efficient approach, using an anonymous type:

使用匿名类型的不太可重用、健壮和高效的方法:

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

回答by Aghilas Yakoub

You can try with this code

您可以尝试使用此代码

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

回答by John Woo

Try,

尝试,

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

回答by cuongle

You can use GroupBywith anonymous type, and then get First:

您可以使用GroupBy匿名类型,然后得到First

list.GroupBy(e => new { 
                          empLoc = e.empLoc, 
                          empPL = e.empPL, 
                          empShift = e.empShift 
                       })

    .Select(g => g.First());

回答by Raj Rao

I was curious about which method would be faster:

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

  1. Using Distinct with a custom IEqualityComparer or
  2. Using the GroupBy method described by Cuong Le.
  1. 将 Distinct 与自定义 IEqualityComparer 或
  2. 使用 Cuong Le 描述的 GroupBy 方法。

I found that depending on the size of the input data and the number of groups, the Distinct method can be a lot more performant. (as the number of groups tends towards the number of elements in the list, distinct runs faster).

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

Code runs in LinqPad!

代码在 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();
        }
    }