Reputation: 908
I'm trying to return a Distinct set of results that are first trimmed using Substring, but when I call "Select" it converts it to an anonymous type. I can't seem to get this to maintain the type "List". I only need to return the fields specified in the Select method.
public List<Facility> GetFacilities() {
var facilities = new List<Facility>();
facilities = _facilityRepository.GetAll().ToList();
var facReturnList =
facilities.Where(x => x.Fac_Name = "Something")
.OrderBy(x => x.Fac_Name).ToList();
var facReturnList2 =
facReturnList.Select(x =>
new { ID = x.Fac_Name.Substring(0, 6),
Fac_Name = x.Fac_Name.Substring(0, 3) })
.Distinct().ToList();
return facReturnList2;
}
I tried adding List<Facility>
after new
, but it says those properties (ID
and Fac_Name
) aren't defined in Facility.
Upvotes: 1
Views: 1641
Reputation: 203836
It sounds like what you really want is a DistinctBy
method. You want to specify some means of indicating that an object is distinct, but you don't want the result to be a collection of that selection, you want the end result to be the starting object. LINQ has no DistinctBy
built in, but implementing one is easy enough:
public static IEnumerable<TSource> DistinctBy<TSource, TKey>(this IEnumerable<TSource> source,
Func<TSource, TKey> keySelector, IEqualityComparer<TKey> comparer = null)
{
comparer = comparer ?? EqualityComparer<TKey>.Default;
HashSet<TKey> knownKeys = new HashSet<TKey>(comparer);
foreach (TSource element in source)
{
if (knownKeys.Add(keySelector(element)))
{
yield return element;
}
}
}
Using that your code can now become:
public List<Facility> GetFacilities()
{
return _facilityRepository.GetAll()
.Where(x => x.Fac_Name == "Something")
.DistinctBy(x => new
{
ID = x.Fac_Name.Substring(0, 6),
Fac_Name = x.Fac_Name.Substring(0, 3)
})
.OrderBy(x => x.Fac_Name)
.ToList();
}
In the event that you have an IQueryable
as opposed to an in memory data set, you can use GroupBy
to get the same behavior. In Linq-to-objects using GroupBy
would be a lot less efficient, but for a query provider it will not be as the database is capable of optimizing this.
public List<Facility> GetFacilities()
{
return _facilityRepository.GetAll()
.Where(x => x.Fac_Name == "Something")
.OrderBy(x => x.Fac_Name)
.GroupBy(x => new
{
ID = x.Fac_Name.Substring(0, 6),
Fac_Name = x.Fac_Name.Substring(0, 3)
})
.Select(group => group.First())
.ToList();
}
Upvotes: 2
Reputation: 7126
The following code is instructing linq to return an anonymous type:
.Select(x => new { ID = x.Fac_Name.Substring(0, 6), Fac_Name = x.Fac_Name.Substring(0, 3) }
You need to create a class for your results
public class Result{
public string ID { get;set; }
public string Fac_Name { get; set; }
}
//Then do
.Select(x => new Result { ID = x.Fac_Name.Substring(0, 6), Fac_Name = x.Fac_Name.Substring(0, 3) }
This ensures you are only returning the information you need
Upvotes: 1
Reputation: 54887
Do you want to initialize new Facility
instances with your results?
var facReturnList2 = facReturnList.Select(x => new Facility { ID = // ...
^ concrete type initializer
Response to edit: Inside the Select
operator, you need to specify the type of the elements that you want to initialize, not their list. Your prior code seems to indicate that Fac_Name
is defined in Facility
, but it obviously wouldn't be defined in List<Facility>
.
Upvotes: 3
Reputation: 126902
You are getting an anonymous type because you are creating it.
.Select(x => new {
If you do not want that, do not do that.
If an existing type already has the name and the precise properties you need, use that. If no type has what you need, create one. Then you can return a proper list or enumerable of that type.
.Select(x => new YourDefinedType {
Upvotes: 3