Выберите различные значения из списка, используя LINQ в С# - программирование
Подтвердить что ты не робот

Выберите различные значения из списка, используя 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?

4b9b3361

Ответ 1

Вы можете реализовать пользовательский 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;
            }
        }
    }
}

Теперь вы можете использовать эту перегрузку 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();

Ответ 2

Вы можете использовать GroupBy с анонимным типом, а затем получить First:

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

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

Ответ 3

Вы можете попробовать с помощью этого кода

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

Ответ 4

Мне было интересно, какой метод будет быстрее:

  • Использование Distinct с пользовательским IEqualityComparer или
  • Использование метода GroupBy, описанного Cuong Le.

Я обнаружил, что в зависимости от размера входных данных и количества групп метод 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();
        }
    }

Ответ 5

Попробуйте,

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