Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/310.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/22.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 在C中使用LINQ从列表中选择不同的值_C#_.net_Linq - Fatal编程技术网

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