简体   繁体   English

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

[英]LINQ advice on selecting distinct elements from a collection

I need to select distinct highways from a roads collection. 我需要从道路收集中选择不同的高速公路。

I suppose I could use LINQ for this. 我想我可以使用LINQ。

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#变体;)

C#: 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) (其中DistinctBy是Jon Skeet优秀的MoreLINQ项目中定义的扩展方法)

EDIT: I didn't get the original requirement, changed OrderBy to GroupBy/Select First. 编辑:我没有得到原始要求,将OrderBy更改为GroupBy / Select First。 You can also simply use Distinct if you override the Equals method to compare the Ids 如果重写Equals方法来比较ID,也可以简单地使用Distinct

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

or in VB.Net: 或者在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 'RoadType Enum

Public Enum RoadType

Residential
Highway
OffRoad
End Enum

'Highway comparer (used in the distinct clause) '公路比较器(用于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

'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 ---输出: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 . 首先,你可以看看这篇博客文章: 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. 这表明您需要创建EqualityComparer<T>而不是简单地将其传递给Distinct运算符。

roads.Where(r => r.RoadType == RoadType.Highway).Distinct(myComparer);

Assuming that myComparer actually implements EqualityComaprer<T> correctly. 假设myComparer实际上正确地实现了EqualityComaprer<T>

You can use a custom equality comparer for Road to use Distinct() : 您可以使用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();   

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM