Moyen le plus rapide d'implémenter la suppression de caractères en double dans String (C#)
Exemple d'entrée: nbHHkRvrXbvkn
Résultat: RrX
Moyen le plus rapide d'implémenter la suppression de caractères en double dans String (C#)
Exemple d'entrée: nbHHkRvrXbvkn
Résultat: RrX
plus rapide que dans moins de lignes-de-code:
var s = "nbHHkRvrXbvkn";
var duplicates = s.Where(ch => s.Count(c => c == ch) > 1);
var result = new string(s.Except(duplicates).ToArray()); // = "RrX"
plus rapide que dans la plus rapide performance serait probablement quelque chose comme ça (ne conserve pas l'ordre):
var h1 = new HashSet<char>();
var h2 = new HashSet<char>();
foreach (var ch in "nbHHkRvrXbvkn")
{
if (!h1.Add(ch))
{
h2.Add(ch);
}
}
h1.ExceptWith(h2); // remove duplicates
var chars = new char[h1.Count];
h1.CopyTo(chars);
var result = new string(chars); // = "RrX"
Test de performance
En cas de doute - le tester :)
Yuriy Faktorovich's answer 00:00:00.2360900 Luke's answer 00:00:00.2225683 My 'few lines' answer 00:00:00.5318395 My 'fast' answer 00:00:00.1842144
Cet algorithme est général, peut être appliquée à toute langue
Voici un assez rapide maintien de l'ordre. Mais je serais un peu inquiet sur la façon dont LINQ fait groupe et où:
string s = "nbHHkRvrXbvkn";
Console.WriteLine(
s.ToCharArray()
.GroupBy(c => c)
.Where(g => g.Count() == 1)
.Aggregate(new StringBuilder(), (b, g) => b.Append(g.Key)));
Edit: Celui-ci bat Luke dans certains cas encore plus lent que celui des DTB, mais il conserve l'ordre
private static string MyMethod(string s)
{
StringBuilder sb = new StringBuilder(s.Length);
foreach (var g in s.ToCharArray().GroupBy(c => c))
if (g.Count() == 1) sb.Append(g.Key);
return sb.ToString();
}
+1. Solution très propre. C'est incroyablement rapide aussi! – dtb
Cette on devrait être assez rapide (et il conserve l'ordre original):
public static string RemoveDuplicates(string source)
{
HashSet<char> found = new HashSet<char>();
HashSet<char> dupes = new HashSet<char>();
foreach (char c in source)
{
if (!found.Add(c))
{
dupes.Add(c);
}
}
StringBuilder sb = new StringBuilder(source.Length);
foreach (char c in source)
{
if (!dupes.Contains(c))
{
sb.Append(c);
}
}
return sb.ToString();
}
Pourquoi pensez-vous que la création d'un StringBuilder probablement trop volumineux prendra moins de temps que de créer de l'espace à la volée? –
@Yuri: J'ai benchmarké! J'ai testé avec des millions de chaînes aléatoires et le pré-dimensionnement du 'StringBuilder' était plus rapide dans la plupart des cas. Bien sûr, dans le monde réel, les cordes ne seraient probablement pas purement aléatoires. Dans cette situation, la différence de performance dépend du rapport entre les dupes et les non-dupes dans la chaîne source. – LukeH
@Yuriy: Je viens de faire un benchmark sur une machine différente (Vista64 vs XP32) et les résultats étaient beaucoup plus proches. Sur la machine 64 bits, il semble ne faire aucune différence si le 'StringBuilder' est pré-alloué ou non. (Dans ce cas, il est probablement logique de ne pas déranger la pré-allocation et de nous sauver de la RAM.) – LukeH
Cela préserve l'ordre et, en fonction de mes tests, est 4 fois plus rapide que d'utiliser un HashSet. Cela suppose que votre plage de caractères est comprise entre 0 et 255 mais vous pouvez l'étendre facilement. Si vous envisagez d'utiliser ceci dans une boucle, déplacez le int[] c = new int[255];
et dans la fonction faites un Array.Clear(c,0,255)
.
private static string RemoveDuplicates(string s)
{
int[] c = new int[255];
for (int i = 0; i < s.Length; i++)
{
c[s[i]]++;
}
StringBuilder sb = new StringBuilder();
for (int i = 0; i < s.Length; i++)
{
if (c[s[i]] == 1) sb.Append(s[i]);
}
return sb.ToString();
}
Très agréable. Grande comparaison des performances aussi. La variation de performance est probablement encore plus visible avec de très grandes chaînes. – Alex
J'ai répété le test de performance dans Release build avec un débogueur détaché (mais la même chaîne d'entrée). Je suis surpris par la performance de la réponse de Yuriy; c'est plutôt rapide! – dtb
@dtb: Ce qui ralentit ma réponse par rapport à la vôtre, c'est que je préserve l'ordre d'origine dans la chaîne de sortie, ce qui nécessite une boucle supplémentaire dans la chaîne d'entrée. La technique que vous et moi utilisons pour trouver les dupes est exactement la même. – LukeH