I need to select distinct highways from a roads collection.
I suppose I could use LINQ for this.
I have (stub code)
Dim roads As List(Of Roads) = myRegion.Roads
Dim highways As New List(Of Highway)
For Each road In roads
If road.RoadType = RoadType.Highway Then
highways.Add(DirectCast(road, Highway))
End If
Next ic
' Now I think sorting them by .Id and then remove duplicates '
Dim myComparer As New HighwayByIdComparer
highways.Sort(myComparer)
C# variants are accepted as well ;)
C#:
return myRegion.Roads
.Where(x => x.RoadType == RoadType.Highway)
.DistinctBy(x => x.Id);
(where DistinctBy is an extension method defined in Jon Skeet's excellent MoreLINQ project)
EDIT: I didn't get the original requirement, changed OrderBy to GroupBy/Select First. You can also simply use Distinct
if you override the Equals method to compare the Ids
var highways = roads.OfType<Highway>()
.GroupBy(x => x.Id)
.Select(x => x.First())
.ToList()
or in VB.Net:
Dim highways = roads.OfType(Of Highway)().
GroupBy(Function(road) road.Id).
Select(Function(x) x.First()).
ToList()
'Road model
Public Class Road
Public Property Id As Integer
Public Property Name As String
Public Property RoadType As RoadType
End Class
'Highway model
Public Class Highway
Public Property Id As Integer
Public Property Name As String
End Class
'RoadType Enum
Public Enum RoadType
Residential
Highway
OffRoad
End Enum
'Highway comparer (used in the distinct clause)
Public Class HigwayNameComparer
Implements IEqualityComparer(Of Highway)
Public Function Equals(ByVal x As Highway, ByVal y As Highway) As Boolean Implements IEqualityComparer(Of Highway).Equals
Return x.Name = y.Name
End Function
Public Function GetHashCode(ByVal obj As Highway) As Integer Implements IEqualityComparer(Of Highway).GetHashCode
Return obj.Name.GetHashCode()
End Function
End Class
'Console app
Sub Main()
Dim roads As New List(Of Road)
roads.Add(New Road() With {.Id = 1, .Name = "Barclays Road", .RoadType = RoadType.Residential})
roads.Add(New Road() With {.Id = 2, .Name = "Effie Road", .RoadType = RoadType.Residential})
roads.Add(New Road() With {.Id = 3, .Name = "Out Road", .RoadType = RoadType.OffRoad})
roads.Add(New Road() With {.Id = 4, .Name = "M4", .RoadType = RoadType.Highway})
roads.Add(New Road() With {.Id = 5, .Name = "M4", .RoadType = RoadType.Highway})
Dim results = (From road In roads Where road.RoadType = RoadType.Highway
Select New Highway With {.Id = road.Id, .Name = road.Name}).Distinct(New HigwayNameComparer())
For Each highway As Highway In results
Console.WriteLine("{0}", highway.Name)
Next
Console.ReadLine()
End Sub
--- Output : M4
First, you could take a look on this blog post: http://blogs.msdn.com/b/csharpfaq/archive/2009/03/25/how-to-use-linq-methods-to-compare-objects-of-custom-types.aspx . This indicates that you need to create EqualityComparer<T>
and than simply pass it to Distinct
operator.
roads.Where(r => r.RoadType == RoadType.Highway).Distinct(myComparer);
Assuming that myComparer actually implements EqualityComaprer<T>
correctly.
You can use a custom equality comparer for Road
to use Distinct()
:
public class RoadComparer : IEqualityComparer<Road>
{
public bool Equals(Road x, Road y)
{
return x.Id == y.Id;
}
public int GetHashCode(Road obj)
{
return obj.Id.GetHashCode();
}
}
var results = myRegion.Roads
.OfType<Highway>()
.Distinct(new RoadComparer())
.OrderBy( road => road.Id)
.ToList();
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.