Equivalente C # di std :: sort e std :: unique
Domanda
Ho un elenco di numeri interi in C #. Desidero rimuovere i duplicati. In C ++ lo eseguivo attraverso gli algoritmi std :: sort e poi std :: unique per un modo molto efficiente di ottenere l'elenco univoco.
Qual è il modo migliore per fare la stessa cosa in C #? In altre parole, sto cercando un modo più elegante per eseguire il seguente codice:
private static int[] unique(int[] ids)
{
IDictionary<int, object> d = new Dictionary<int, object>();
foreach(int i in ids)
d[i] = null;
int[] results = new int[d.Count];
int j = 0;
foreach(int id in d.Keys)
results[j++] = id;
return results;
}
Soluzione
Quale versione di .NET stai usando?
In .NET 3.5 è semplice come chiamare Metodo di estensione Distinct () e quindi ToArray () se hai davvero bisogno di nuovo un array.
Ad esempio:
int[] x = new[] { 1, 4, 23, 4, 1 };
int[] distinct = x.Distinct().ToArray();
// distinct is now { 1, 4, 23 } (but not necessarily in that order)
Altri suggerimenti
se consideri i metodi STL come "molto efficienti", usa quindi:
var vals = new List<int> { 1, 2, 3, 2, 1, 2, 3, 2, 3, 4, 3, 2, 3 };
vals.Sort();
var uniques = new HashSet<int>(vals);
Per 2,0 equivalenti
List<int> vals = new List<int>();
vals.Add(1);
vals.Add(2);
vals.Add(3);
vals.Add(2);
...
vals.Sort();
List<int> uniques = new List<int>();
vals.ForEach(delegate(int v) {
if (!uniques.Contains(v)) uniques.Add(v);
});
Anche con .NET 2.0, potresti ottenere lo stesso con LINQBridge . Questo sarà più facile da usare con C # 3.0 (anche con .NET 2.0), ma dovrebbe essere utilizzabile con C # 2.0 e .NET 2.0 - dovresti semplicemente usare Enumerable.Distinct (x) anziché x.Distinct ();
Naturalmente, in definitiva, queste sono solo versioni preconfezionate del codice che hai pubblicato in precedenza (cose da dare o prendere come blocchi di iteratori), quindi puoi semplicemente inserire quel codice in una classe di utilità e (ri) utilizzarlo da lì.
Purtroppo ho solo .NET 2.0 con cui lavorare
In una nota a metà strada, C # ha un System.Array.Sort metodo statico che puoi utilizzare per ordinare array reali senza utilizzare una raccolta.
Non so quanto sia grande la tua raccolta, ma se non hai a che fare con migliaia di numeri interi questo potrebbe essere abbastanza buono:
public IEnumerable<int> unique(int[] ids)
{
List<int> l = new List<int>();
foreach (int id in ids)
{
if (!l.Contains(id))
{
l.Add(id);
yield return id;
}
}
}
private static List<T> GetUnique<T>(List<T> list) where T : IEquatable<T>
{
list.Sort();
int count = list.Count;
List<T> unique = new List<T>(count);
T last = default(T);
for (int i = 0; i < count; i++)
{
T val = list[i];
if (i != 0 && last.Equals(val)) continue;
last = val;
unique.Add(val);
}
return unique;
}