Perf comparison of @S.Akbari's and @Mick's solutions using BenchmarkDotNet
EDIT:
SAkbari_FindDistinctWithoutLinq has redundant call to ContainsKey, so i added impoved and faster version: SAkbari_FindDistinctWithoutLinq2
Method | Mean | Error | StdDev |
--------------------------------- |---------:|----------:|----------:|
SAkbari_FindDistinctWithoutLinq | 4.021 us | 0.0723 us | 0.0676 us |
SAkbari_FindDistinctWithoutLinq2 | 3.930 us | 0.0529 us | 0.0495 us |
SAkbari_FindDistinctLinq | 5.597 us | 0.0264 us | 0.0234 us |
Mick_UsingGetHashCode | 6.339 us | 0.0265 us | 0.0248 us |
BenchmarkDotNet=v0.10.13, OS=Windows 10 Redstone 3 [1709, Fall Creators Update] (10.0.16299.248)
Intel Core i7-7700 CPU 3.60GHz (Kaby Lake), 1 CPU, 8 logical cores and 4 physical cores
Frequency=3515625 Hz, Resolution=284.4444 ns, Timer=TSC
.NET Core SDK=2.1.100
[Host] : .NET Core 2.0.5 (CoreCLR 4.6.26020.03, CoreFX 4.6.26018.01), 64bit RyuJIT
DefaultJob : .NET Core 2.0.5 (CoreCLR 4.6.26020.03, CoreFX 4.6.26018.01), 64bit RyuJIT
Benchmark:
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Running;
using System;
using System.Collections.Generic;
using System.Linq;
namespace ConsoleApp1
{
public class Program
{
List<int[]> intArrList = new List<int[]>
{
new int[] { 0, 0, 0 },
new int[] { 20, 30, 10, 4, 6 }, //this
new int[] { 1, 2, 5 },
new int[] { 20, 30, 10, 4, 6 }, //this
new int[] { 12, 22, 54 },
new int[] { 1, 2, 6, 7, 8 },
new int[] { 0, 0, 0, 0 }
};
[Benchmark]
public List<int[]> SAkbari_FindDistinctWithoutLinq() => FindDistinctWithoutLinq(intArrList);
[Benchmark]
public List<int[]> SAkbari_FindDistinctWithoutLinq2() => FindDistinctWithoutLinq2(intArrList);
[Benchmark]
public List<int[]> SAkbari_FindDistinctLinq() => FindDistinctLinq(intArrList);
[Benchmark]
public List<int[]> Mick_UsingGetHashCode() => FindDistinctLinq(intArrList);
static void Main(string[] args)
{
var summary = BenchmarkRunner.Run<Program>();
}
public static List<int[]> FindDistinctWithoutLinq(List<int[]> lst)
{
var dic = new Dictionary<string, int[]>();
foreach (var item in lst)
{
string key = string.Join(",", item.OrderBy(c => c));
if (!dic.ContainsKey(key))
{
dic.Add(key, item);
}
}
return dic.Values.ToList();
}
public static List<int[]> FindDistinctWithoutLinq2(List<int[]> lst)
{
var dic = new Dictionary<string, int[]>();
foreach (var item in lst)
dic.TryAdd(string.Join(",", item.OrderBy(c => c)), item);
return dic.Values.ToList();
}
public static List<int[]> FindDistinctLinq(List<int[]> lst)
{
return lst.GroupBy(p => string.Join(", ", p.OrderBy(c => c)))
.Select(c => c.First().ToArray()).ToList();
}
public static List<int[]> UsingGetHashCode(List<int[]> lst)
{
return lst.Select(a => a.OrderBy(e => e).ToArray()).Distinct(new IntArrayEqualityComparer()).ToList();
}
}
public class IntArrayEqualityComparer : IEqualityComparer<int[]>
{
public bool Equals(int[] x, int[] y)
{
return ArraysEqual(x, y);
}
public int GetHashCode(int[] obj)
{
int hc = obj.Length;
for (int i = 0; i < obj.Length; ++i)
{
hc = unchecked(hc * 17 + obj[i]);
}
return hc;
}
static bool ArraysEqual<T>(T[] a1, T[] a2)
{
if (ReferenceEquals(a1, a2))
return true;
if (a1 == null || a2 == null)
return false;
if (a1.Length != a2.Length)
return false;
EqualityComparer<T> comparer = EqualityComparer<T>.Default;
for (int i = 0; i < a1.Length; i++)
{
if (!comparer.Equals(a1[i], a2[i])) return false;
}
return true;
}
}
}