LINQ选择从集合中不同元素的建议

3

我需要从一组道路中选择不同的高速公路。

我想我可以使用LINQ来实现这个目的。

我有(存根代码)

  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#的变体也被接受 ;)

5个回答

4

C#:

return myRegion.Roads
    .Where(x => x.RoadType == RoadType.Highway)
    .DistinctBy(x => x.Id);

(其中DistinctBy是Jon Skeet出色的MoreLINQ项目中定义的扩展方法)


好的...但是我没有完成我的代码,因为我需要选择不同(具有不同.ID)的元素。 - serhio
我不确定在商业专有项目中是否可以使用 MoreLINQ。 - serhio
从源代码中汲取灵感,然后编写自己的实现 - http://morelinq.googlecode.com/svn/trunk/MoreLinq/DistinctBy.cs - Ian Nelson
2
好的...也许你不需要OrderBy,因为我只是为了更容易地消除重复项而进行了排序... - serhio
另外,我应该指出 OfType<Highway>road.RoadType = RoadType.Highway 的性能要差。 - serhio

1
"路模型"
Public Class Road
Public Property Id As Integer
Public Property Name As String
Public Property RoadType As RoadType
End Class 

高速公路模型
Public Class Highway
Public Property Id As Integer
Public Property Name As String 
End Class

'道路类型枚举

Public Enum RoadType

Residential
Highway
OffRoad
End Enum

高速公路比较器(用于distinct子句)
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

控制台应用程序
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 

--- 输出:M4


1

编辑:我没有理解原始需求,将 OrderBy 更改为 GroupBy/Select First。如果您重写 Equals 方法来比较 Id,则还可以简单地使用 Distinct

var highways = roads.OfType<Highway>()
          .GroupBy(x => x.Id)
          .Select(x => x.First())
          .ToList()

或者在 VB.Net 中:

Dim highways = roads.OfType(Of Highway)().
       GroupBy(Function(road) road.Id).
       Select(Function(x) x.First()).
       ToList()

2
OfType很聪明,但你错过了Distinct。 - H H
在我看来,最好的解决方案是,您也可以删除HighwayByIdComparer。 - Bas
而且没有调用OrderBy,这是一个(半路)解决方案,以获得Distinct。 - H H

0

Dim myComparer As New HighwayByIdComparer - H H

0

您可以使用自定义的相等比较器来为 Road 使用 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();   

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接