I am trying to filter a list of objects by multiple criteria. First of all, if the Name and Code are the same for two or more records, I only want to return one. However, if the Status of one is "suspended" and the Status of the second is "rented", I only want to return the record with "suspended" status. This is what I've got so far:
public class Customer
{
public string UnitName { get; set; }
public string Code { get; set; }
public string Name { get; set; }
public string Phone { get; set; }
public string Status { get; set; }
}
public static IEnumerable<Customer> FilterDuplicates(IEnumerable<Customer> customers)
{
return customers
.GroupBy(c => new {c.Name, c.Code})
.Select(g => g.First());
}
For example, the following data should return Mister Twister, Frank Furter and the record where the status is "suspended" for Jane Jones:
{
"unitName": "A22",
"code": "00122",
"status": "rented",
"phone": "2125551212",
"name": "Jones, Jane"
},
{
"unitName": "A07",
"code": "00122",
"status": "suspended",
"phone": "2125551212",
"name": "Jones, Jane"
},
{
"unitName": "C19",
"code": "00222",
"status": "suspended",
"phone": "2125557777",
"name": "Furter, Frank"
},
{
"unitName": "B14",
"code": "00333",
"status": "rented",
"phone": "2125559999",
"name": "Twister, Mister"
}
You should order the contents of each group and then you can select which one you want:
return customers
.GroupBy(c => new {c.Name, c.Code})
.Select(g => g.OrderByDescending(c => c.status).First());
NOTE: This is essentially a particular implementation of DistinctBy
, which in full general form I implement with:
public static IEnumerable<T> DistinctBy<T, TKey>(this IEnumerable<T> src, Func<T, TKey> keySelector, Func<IGrouping<TKey, T>, T> pickFn, IEqualityComparer<TKey> comparer = null) =>
src.GroupBy(keySelector, comparer).Select(pickFn);
Which you could then use as
return customers.DistinctBy(c => new { c.Name, c.Code }),
g => g.OrderByDescending(c => c.status).First());