Ozgur Ozcitak
Ozgur Ozcitak

Reputation: 10619

Selecting unique elements from a List in C#

How do I select the unique elements from the list {0, 1, 2, 2, 2, 3, 4, 4, 5} so that I get {0, 1, 3, 5}, effectively removing all instances of the repeated elements {2, 4}?

Upvotes: 27

Views: 62273

Answers (10)

tmaj
tmaj

Reputation: 35037

Here's a solution with no LINQ:

var numbers = new[] { 0, 1, 2, 2, 2, 3, 4, 4, 5 };

// This assumes the numbers are sorted
var noRepeats = new List<int>();
int temp = numbers[0]; // Or .First() if using IEnumerable
var count = 1;
for(int i = 1; i < numbers.Length; i++) // Or foreach (var n in numbers.Skip(1)) if using IEnumerable
{
    if (numbers[i] == temp) count++;
    else
    {
        if(count == 1) noRepeats.Add(temp);
        temp = numbers[i];
        count = 1;
    }
}
if(count == 1) noRepeats.Add(temp);

Console.WriteLine($"[{string.Join(separator: ",", values: numbers)}] -> [{string.Join(separator: ",", values: noRepeats)}]");

This prints:

[0,1,2,2,2,3,4,4,5] -> [0,1,3,5]

Upvotes: 0

Atomic Star
Atomic Star

Reputation: 5517

Here is another way that works if you have complex type objects in your List and want to get the unique values of a property:

var uniqueValues= myItems.Select(k => k.MyProperty)
                  .GroupBy(g => g)
                  .Where(c => c.Count() == 1)
                  .Select(k => k.Key)
                  .ToList();

Or to get distinct values:

var distinctValues = myItems.Select(p => p.MyProperty)
                            .Distinct()
                            .ToList();

If your property is also a complex type you can create a custom comparer for the Distinct(), such as Distinct(OrderComparer), where OrderComparer could look like:

public class OrderComparer : IEqualityComparer<Order>
{
    public bool Equals(Order o1, Order o2)
    {
        return o1.OrderID == o2.OrderID;
    }

    public int GetHashCode(Order obj)
    {
        return obj.OrderID.GetHashCode();
    }
}

Upvotes: 9

Matt Howells
Matt Howells

Reputation: 41266

C# 2.0 solution:

static IEnumerable<T> GetUniques<T>(IEnumerable<T> things)
{
    Dictionary<T, int> counts = new Dictionary<T, int>();

    foreach (T item in things)
    {
        int count;
        if (counts.TryGetValue(item, out count))
            counts[item] = ++count;
        else
            counts.Add(item, 1);
    }

    foreach (KeyValuePair<T, int> kvp in counts)
    {
        if (kvp.Value == 1)
            yield return kvp.Key;
    }
}

Upvotes: 10

Bryan Watts
Bryan Watts

Reputation: 45445

var numbers = new[] { 0, 1, 2, 2, 2, 3, 4, 4, 5 };

var uniqueNumbers =
    from n in numbers
    group n by n into nGroup
    where nGroup.Count() == 1
    select nGroup.Key;

// { 0, 1, 3, 5 }

Upvotes: 38

tmaj
tmaj

Reputation: 35037

There are many ways to skin a cat, but HashSet seems made for the task here.

var numbers = new[] { 0, 1, 2, 2, 2, 3, 4, 4, 5 };

HashSet<int> r = new HashSet<int>(numbers);

foreach( int i in r ) {
    Console.Write( "{0} ", i );
}

The output:

0 1 2 3 4 5

Upvotes: 2

Murilo Beltrame
Murilo Beltrame

Reputation: 81

In .Net 2.0 I`m pretty sure about this solution:

public IEnumerable<T> Distinct<T>(IEnumerable<T> source)
{
     List<T> uniques = new List<T>();
     foreach (T item in source)
     {
         if (!uniques.Contains(item)) uniques.Add(item);
     }
     return uniques;
}

Upvotes: -1

Barbaros Alp
Barbaros Alp

Reputation: 6434

With lambda..

var all = new[] {0,1,1,2,3,4,4,4,5,6,7,8,8}.ToList();
var unique = all.GroupBy(i => i).Where(i => i.Count() == 1).Select(i=>i.Key);

Upvotes: 14

Robert Rossney
Robert Rossney

Reputation: 96750

I believe Matt meant to say:

 static IEnumerable<T> GetUniques<T>(IEnumerable<T> things)
 {
     Dictionary<T, bool> uniques = new Dictionary<T, bool>();
     foreach (T item in things)
     {
         if (!(uniques.ContainsKey(item)))
         {
             uniques.Add(item, true);
         }
     }
     return uniques.Keys;
 }

Upvotes: 2

Corey Trager
Corey Trager

Reputation: 23133

If Linq isn't available to you because you have to support legacy code that can't be upgraded, then declare a Dictionary, where the first int is the number and the second int is the number of occurences. Loop through your List, loading up your Dictionary. When you're done, loop through your Dictionary selecting only those elements where the number of occurences is 1.

Upvotes: 3

CVertex
CVertex

Reputation: 18237

var nums = new int{ 0...4,4,5};
var distinct = nums.Distinct();

make sure you're using Linq and .NET framework 3.5.

Upvotes: 20

Related Questions