Search code examples
c#vb.netlinqlinq-expressions

Linq Expression: Perform Distinct on a list dynamic property


I've a list of objects on which I need to perform a Distinct() function. Currently I use the following code.

Return choices = displaylist
    .Select(Function(x) x.Zone)
    .ToList
    .Distinct()

The above code works well for me. However I need to expand this code into something that allows me to provide any property name and return me the distinct values of the list. My custom object has 20+ properties e.g. Zone, Region, Department, etc.

I need to make a flexible function that I give any property name and it returns distinct. Something like this pseudo:

Function GetDistincts(PROPERTYNAME as string)
    Return choices = displaylist
        .Select(Function(x) x.[PROPERTYNAME])
        .ToList
        .Distinct()
End Function

I believe this is job for Linq Expressions. But I'm no good at it. So need assistance here.

Thanks!


Solution

  • You can use the power of the extension methods and the Generic Types to write a generic extension method to obtain distinct result of every List(Of T):

    VB

    Dim objects = New List(Of TestObject)()
    objects.Add(New TestObject(1, "Test1"))
    objects.Add(New TestObject(1, "Test2"))
    objects.Add(New TestObject(1, "Test3"))
    objects.Add(New TestObject(2, "Test4"))
    objects.Add(New TestObject(2, "Test5"))
    objects.Add(New TestObject(2, "Test6"))
    
    Dim t As List(Of Integer) = objects.GetDistict(Of Integer, TestObject)("Zone")
    
    Public Class TestObject
        Public Property Zone As Integer
        Public Property Address As String
    
        Public Sub New(z As Integer, a As String)
            Zone = z
            Address = a
        End Sub
    End Class
    
        Public NotInheritable Class DistinctExtension
        Private Sub New()
        End Sub
        <System.Runtime.CompilerServices.Extension> _
        Public Shared Function GetDistict(Of T, S)(source As List(Of S), name As String) As List(Of T)
            Return source.[Select](Function(x) DirectCast(x.[GetType]().GetProperty(name).GetValue(x), T)).Distinct().ToList()
        End Function
    
    End Class
    

    C#

    var objects = new List<TestObject>();
                objects.Add(new TestObject(1,"Test1"));
                objects.Add(new TestObject(1,"Test2"));
                objects.Add(new TestObject(1,"Test3"));
                objects.Add(new TestObject(2,"Test4"));
                objects.Add(new TestObject(2,"Test5"));
                objects.Add(new TestObject(2,"Test6"));
    
            List<int> t = objects.GetDistict<int, TestObject>("Zone");
    
    public static class DistinctExtension
    {
        public static List<T> GetDistict<T,S>(this List<S> source, string name)
        {
            return source.Select(x => (T)x.GetType().GetProperty(name).GetValue(x)).Distinct().ToList();
        }
    
    }
    
    public class TestObject
    {
        public int Zone { get; set; }
        public string Address { get; set; }
    
        public TestObject(int zone, string address)
        {
            Zone = zone;
            Address = address;
        }
    }