Select First Row In Group using Custom Comparer

We have a requirement for a list of itineraries with multple itinerary items show only single itinerary in the list with details of one of the items  selected based on some custom sorting logic. So I needed to group by itinerary ID and sort by custom Comparison and select the first in each group.

 

Below is a LinqPad file that I've used for testing:
 

void Main()
{
// http://smehrozalam.wordpress.com/2009/12/29/linq-how-to-get-the-latest-last-record-with-a-group-by-clause/
// http://stackoverflow.com/questions/6963707/linq-query-group-by-and-selecting-first-items/7456167#7456167
var rows=new List<MyRow>()
{
new MyRow(1,ProductType.F,new DateTime(2012,01,01),"A")
,new MyRow( 1,ProductType.C, new DateTime(2012,01,01),"B")
,new MyRow(1,ProductType.H, new DateTime(2012,01,01),"C")
,new MyRow(2,ProductType.C, new DateTime(2012,01,01),"D")
,new MyRow(2,ProductType.Hnew DateTime(2012,01,01),"E")
,new MyRow(3,ProductType.F, new DateTime(2012,02,01),"F")
,new MyRow(3,ProductType.F, new DateTime(2012,03,01),"G")
,new MyRow(3,ProductType.F, new DateTime(2012,01,05),"H")
,new MyRow(3,ProductType.H, new DateTime(2011,01,01),"I")
,new MyRow(4,ProductType.C, new DateTime(2012,01,01),"J")
,new MyRow(5,ProductType.H, new DateTime(2012,01,01),"K")
,new MyRow(6,ProductType.C, new DateTime(2012,01,01),"L")
,new MyRow(6,ProductType.H, new DateTime(2011,01,01),"M")

} ;

var firstsInGroups= from p in rows
//where conditions or joins with other tables to be included here
     group p by p.ID into grp
select grp.First();

firstsInGroups.Dump();

var firstsByCompareInGroups= from p in rows
group p by p.ID into grp
select grp.OrderBy(a => a, new CompareRows()).First();
firstsByCompareInGroups.Dump();

}

// Define other methods and classes here
public class  MyRow
{ public int ID;
public ProductType Type;
  public DateTime StartTime;
public string OtherData;

  public MyRow( int id,  ProductType type,   DateTime startTime,   string otherData)
{
ID=id;
   Type=type;
   StartTime=startTime;
  OtherData= otherData;
}
  }
public enum ProductType
  {F,C,H}

// http://msdn.microsoft.com/en-us/library/bb549422.aspx
  public class CompareRows : IComparer<MyRow>
{
// Because the class implements IComparer, it must define a
// Compare method. The method returns a signed integer that indicates
// whether s1 > s2 (return is greater than 0), s1 < s2 (return is negative),
// or s1 equals s2 (return value is 0). This Compare method compares strings.
public int Compare(MyRow r1, MyRow r2)
{
if(r1.Type==r2.Type)
{
return DateTime.Compare(r1.StartTime, r2.StartTime);
}
//F is the best type
else if (r1.Type==ProductType.F)
{
   return -1;
}
else if (r2.Type==ProductType.F)
{
   return 1;
}
else //for C and H min Date is better
{ int compareDates=DateTime.Compare(r1.StartTime.Date, r2.StartTime.Date);
   if(compareDates!=0)
{
return compareDates;
}
else//For the same date C is better
{
if (r1.Type==ProductType.C)
{
return -1;
}
else if (r2.Type==ProductType.C)
{
return 1;
}
Debug.Assert(false,"should not be here");
return 0;
}
}
}
}

 

posted @ Monday, September 19, 2011 6:43 AM
Print

Comments on this entry:

# re: Select First Row In Group using Custom Comparer

Left by Mike Calvert at 9/21/2011 2:09 PM
Gravatar
Using the comparer interface is definitely a great tool for sorting collections. Mostly I've seen this functionality wrapped up, and it is automatically implemented into a lot of collections. It brings up a good point about whether the object itself should be responsible for knowing the sort order or if a collection should be. Check out my article at www.blogscrum.com on using the IComparable.

Your comment:



(not displayed)


 
 
 
 
 

Live Comment Preview:

 
«May»
SunMonTueWedThuFriSat
293012345
6789101112
13141516171819
20212223242526
272829303112
3456789