score:39

Accepted answer

you could implement a custom 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:

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

score:0

try,

var newlist = 
(
from x in empcollection
select new {loc = x.emploc, pl = x.emppl, shift = x.empshift}
).distinct();

score:3

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.

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).

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

score:15

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

score:42

you can use groupby with anonymous type, and then get first:

list.groupby(e => new { 
                          emploc = e.emploc, 
                          emppl = e.emppl, 
                          empshift = e.empshift 
                       })

    .select(g => g.first());

Related Query

More Query from same tag