tags:

views:

512

answers:

4

Hi Gurus,

I am trying to figure out if I can use LINQ to provide me with the distinct values of some data I have in a DataTable (FirstName, LastName, QTY). I can get the distinct values and fill my List, but I have to run two different LINQ queries to get it....I am sure there is a better way to do it :)

Any suggestions would be greatly appreciated (very new to LINQ)

Code:

public static List<StudentData> LinqDistinct(DataTable dt)
{
      DataTable linqTable = dt;

       //get the distinct values
        var query =
            (from names in dt.AsEnumerable()
             select new {
                 FirstName = names.Field<string>("FirstName"),
                 LastName = names.Field<string>("LastName")
             }).Distinct();


        //fill my list with the distinct values
        List<StudentData> sList = (from sa in query.AsEnumerable()
                                   select new StudentData
                                              {
                                                  FirstName = sa.FirstName,
                                                  LastName = sa.LastName
                                                  //Qty = names.Field<int>("Qty")

                                                 }).ToList();                                               



        return sList;}
A: 

Pretty sure you could just do this...

List<StudentData> sList = (from names in dt.AsEnumerable().Distinct() // I am not sure if you even have to call AsEnumerable()
                 select new StudentData() {
                     FirstName = names.Field<string>("FirstName"),
                     LastName = names.Field<string>("LastName")
                 }).ToList();
J.13.L
This might not fly, because you're asking for a distinct list of DataRow objects, which will probably do reference comparisons and decide that your data is already distinct. But you do need the AsEnumerable() call on the DataTable (just not on the query, in the original code).
Joel Mueller
The above still isn't giving me the distinct rows I was looking for...thanks for the response though :) S
scarpacci
A: 

You could use GroupBy:

public static List<StudentData> LinqDistinct(DataTable dt)
{
    List<StudentData> results = dt.AsEnumerable()
        .GroupBy(row => 
        {
            FirstName = row.Field<string>("FirstName"),
            LastName = row.Field<string>("LastName")
        })
        .Select(group => new StudentData
        {
            FirstName = group.Key.FirstName,
            LastName = group.Key.LastName,
            Qty = group.Count()
        })
        .ToList();

    return results;
}

class StudentData
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public int Qty { get; set; }
}
Ecyrb
I will give this one a shot
scarpacci
+1  A: 

It's not clear from your question whether the quantity is a value in your DataTable, or a count of the number of duplicates for a given item, as in Ecyrb's answer. However, if your StudentData class implements IEquatable<StudentData> or overrides the Equals method, this should work:

public static List<StudentData> LinqDistinct(DataTable dt)
{
    return dt.AsEnumerable()
             .Select(row => new StudentData
                            {
                                FirstName = row.Field<string>("FirstName"),
                                LastName = row.Field<string>("LastName"),
                                Qty = row.Field<int>("Qty")
                            })
             .Distinct()
             .ToList();
}

If StudentData doesn't support value comparison, and you can't add that support to the class, you may have to create an implementation of IEqualityComparer<StudentData> and pass that into the Distinct method.

Joel Mueller
I apologize....FirstName, LastName, QTY are in the datatable, but I only want to return FirstName/LastName. I will give your method a shot. Thanks!
scarpacci
+1 I think this is your best bet...
J.13.L
This worked! Thanks Joel!
scarpacci
+1  A: 

Any reason not to simply do the projection after the distinct, you might need an AsEnumerable() after the Distinct but that's not a big deal.

public static List<StudentData> LinqDistinct(DataTable dt)
{
    DataTable linqTable = dt;
    return
        (from names in dt.AsEnumerable()
         select new {
             FirstName = names.Field<string>("FirstName"),
             LastName = names.Field<string>("LastName")
         }).Distinct().Select(x =>
             new StudentData() { FirstName=x.FirstName, LastName=x.LastName})
             .ToList();
}
ShuggyCoUk
Just saw this....this is perfect! Now I don't have to even use the IEqualityComparer!. Thanks.
scarpacci