How to Obtain a Distinct List Based on One or More Properties in C#

Bilal Shahid Feb 02, 2024
  1. Use GroupBy() and Select() to Obtain a Distinct List Based on One Property in C#
  2. Use GroupBy() and Select() to Obtain a Distinct List Based on One or More Properties in C#
  3. Use DistinctBy to Obtain a Distinct List Based on One or More Properties in C#
How to Obtain a Distinct List Based on One or More Properties in C#

Today we will be looking at how we can use Distinct() in LINQ on multiple objects with the same properties containing different values. As a start, take a look at the example below.

Suppose you have three objects: CAR one, CAR two, and CAR three. CAR one and CAR two contain build values of 2, but CAR three has a build value of 4.

When calling Distinct() on the three objects, the result should only include CAR one and CAR three or CAR two and CAR three as they both contain distinct values.

This article will discuss obtaining a distinct list based on one or more properties in C#.

Use GroupBy() and Select() to Obtain a Distinct List Based on One Property in C#

So before we start our example, let’s first add the LINQ library to our code:

using SYSTEM.Linq;

Then let’s go forward and define our CAR class as follows:

class CAR {
  public int id;

  public CAR(int id) {
    this.id = id;
  }
}

And then, in the Main, let’s define a few objects:

CAR one = new CAR(4);
CAR two = new CAR(4);
CAR three = new CAR(6);

List<CAR> cars = new List<CAR>();
cars.Add(one);
cars.Add(two);
cars.Add(three);

We have also made a list and added the three objects to it. We will trim the same property objects and only consider one from them.

We will create a new list, then use the GroupBY() clause. And finally, the First() to pick out the winner.

List<CAR> distinct_c = cars.GroupBy(p => p.id).Select(g => g.First()).ToList();
for (int i = 0; i < distinct_c.Count(); i++) {
  Console.Write(distinct_c[i].id + " ");
}

The result will come out as follows:

4 6

These were the two distinct IDs in each of the three objects. The whole code is as follows:

class pointer {
  class CAR {
    public int id;

    public CAR(int id) {
      this.id = id;
    }
  }

  public static void Main(String[] args) {
    CAR one = new CAR(4);
    CAR two = new CAR(4);
    CAR three = new CAR(6);

    List<CAR> cars = new List<CAR>();
    cars.Add(one);
    cars.Add(two);
    cars.Add(three);

    List<CAR> distinct_c = cars.GroupBy(p => p.id).Select(g => g.First()).ToList();
    for (int i = 0; i < distinct_c.Count(); i++) {
      Console.Write(distinct_c[i].id + " ");
    }
  }
}

Insert the above code in your namespace and then play with it.

Use GroupBy() and Select() to Obtain a Distinct List Based on One or More Properties in C#

What if we had one more property called color along with id and still wanted to pick out the distinct one. Let’s add the color property to our CAR class as follows:

class CAR {
  public int id;
  public string color;

  public CAR(int id, string color) {
    this.id = id;
    this.color = color;
  }
}

If you were to, however, now call the function with the same syntax as above:

CAR one = new CAR(4, "red");
CAR two = new CAR(4, "blue");
CAR three = new CAR(6, "blue");

List<CAR> cars = new List<CAR>();
cars.Add(one);
cars.Add(two);
cars.Add(three);

List<CAR> distinct_c = cars.GroupBy(p => p.id).Select(g => g.First()).ToList();
for (int i = 0; i < distinct_c.Count(); i++) {
  Console.Write(distinct_c[i].id + " ");
}

The output would stay the same as 4 6. Because p still groups only by p => p.id. But now that we want to distinct by color as well, we can do something as follows:

List<CAR> distinct_c = cars.GroupBy(p => (p.id, p.color)).Select(g => g.First()).ToList();
for (int i = 0; i < distinct_c.Count(); i++) {
  Console.Write(distinct_c[i].id + " ");
}

So what will be the result? Because the three objects have all different combinations of ID and CAR as; (4, red), (4, blue) and (6, blue). Hence there is a distinction between all objects.

The output will now be:

4 4 6

The complete code is provided below:

using System;
using System.Collections.Generic;
using System.Linq;

static class pointer {
  class CAR {
    public int id;
    public string color;

    public CAR(int id, string color) {
      this.id = id;
      this.color = color;
    }
  }

  public static void Main(String[] args) {
    CAR one = new CAR(4, "red");
    CAR two = new CAR(4, "blue");
    CAR three = new CAR(6, "blue");

    List<CAR> cars = new List<CAR>();
    cars.Add(one);
    cars.Add(two);
    cars.Add(three);

    List<CAR> distinct_c = cars.GroupBy(p => (p.id, p.color)).Select(g => g.First()).ToList();
    for (int i = 0; i < distinct_c.Count(); i++) {
      Console.Write(distinct_c[i].id + " ");
    }
  }
}

You can even add a Where condition to check if the p.id is not null and then call it:

List<CAR> distinct_c =
    cars.Where(p => p.id != null).GroupBy(p => (p.id, p.color)).Select(g => g.First()).ToList();
for (int i = 0; i < distinct_c.Count(); i++) {
  Console.Write(distinct_c[i].id + " ");
}

The result will also be the same.

Points to Consider While Using First() in C#

Sometimes, you can get away with FirstorDefault(). Another function that does the same thing as First(), but if there is no first element, it will just return a default value.

It can be used to work around errors at null values.

Use DistinctBy to Obtain a Distinct List Based on One or More Properties in C#

You can write a function that can return distinct values in C#.

One way to do it can be to use hashtables that can take a key and a value and map it together. You can write a function like that as follows:

public static IEnumerable<S> DistinctBy<S, K>(this IEnumerable<S> source, Func<S, K> keySelector) {
  HashSet<K> seen = new HashSet<K>();
  foreach (S element in source) {
    if (seen.Add(keySelector(element))) {
      yield return element;
    }
  }
}

Before this, however, ensure to download MORELINQ and configure it for your code.

var q = cars.DistinctBy(p => p.id);

And then, you can print the contents of this variable q and get the answer. The complete code is shown below:

using System;
using System.Collections.Generic;
using System.Text;
using System.Linq;
using MoreLinq;

namespace jinlku_console {
  static class pointer {
    class CAR {
      public int id;
      public string color;

      public CAR(int id, string color) {
        this.id = id;
        this.color = color;
      }
    }

    public static IEnumerable<S> DistinctBy<S, K>(this IEnumerable<S> source,
                                                  Func<S, K> keySelector) {
      HashSet<K> seen = new HashSet<K>();
      foreach (S element in source) {
        if (seen.Add(keySelector(element))) {
          yield return element;
        }
      }
    }

    public static void Main(String[] args) {
      CAR one = new CAR(4, "red");
      CAR two = new CAR(4, "blue");
      CAR three = new CAR(6, "blue");

      List<CAR> cars = new List<CAR>();
      cars.Add(one);
      cars.Add(two);
      cars.Add(three);

      var q = cars.DistinctBy(p => p.id);

      Console.WriteLine(q.Count());

      List<CAR> distinct_c = cars.GroupBy(p => (p.id, p.color)).Select(g => g.First()).ToList();
      for (int i = 0; i < distinct_c.Count(); i++) {
        Console.Write(distinct_c[i].id + " ");
      }
    }
  }
}

Another Simple Solution to Obtain a Distinct List Based on One or More Properties in C#

One other way to write the same query can be as follows:

var un = from car in cars group car by new(car.id) into mg select mg.First();

However, to use this, you may need to update your language to 9.0 or greater.

Author: Bilal Shahid
Bilal Shahid avatar Bilal Shahid avatar

Hello, I am Bilal, a research enthusiast who tends to break and make code from scratch. I dwell deep into the latest issues faced by the developer community and provide answers and different solutions. Apart from that, I am just another normal developer with a laptop, a mug of coffee, some biscuits and a thick spectacle!

GitHub

Related Article - Csharp LINQ