2009-08-16 6 views
3

Un ami m'a demandé comment améliorer du code avec LINQ. Comment feriez-vous une comparaison caractère par caractère entre deux chaînes pour compter le nombre de correspondances à un index? Voici le code original, pourrait-il être amélioré avec LINQ?Compter les caractères correspondants entre deux chaînes à l'aide de LINQ

private int Fitness(string individual, string target) 
    { 
     int sum = 0; 
     for (int i = 0; i < individual.Length; i++) 
      if (individual[i] == target[i]) sum++; 
     return sum; 
    } 

Répondre

5
return Enumerable.Range(0, individual.Length) 
       .Count(i => individual[i] == target[i]); 

Un plus infaillible moyen serait (l'extrait ci-dessus échouera si target est plus courte que individual):

return Enumerable.Range(0, Math.Min(individual.Length, target.Length)) 
       .Count(i => individual[i] == target[i]); 

Je crois que le code est correct tout comme . Enumerable.Range méthode prend deux arguments. Le premier est l'index de départ (devrait être 0), le second est le nombre d'éléments. L'extrait de code complet pour tester et assurez-vous:

class Program { 
    static void Main(string[] args) { 
     Console.WriteLine(Fitness("hello", "world")); 
    } 
    static int Fitness(string individual, string target) { 
     return Enumerable.Range(0, Math.Min(individual.Length, target.Length)) 
         .Count(i => individual[i] == target[i]); 
    } 
} 
+0

Nécessaire de faire Longueur-1 puisque les tableaux sont basés sur zéro –

+2

Le deuxième argument de 'Range' est le compte, pas le dernier élément. –

+0

C'est pourquoi vous devez faire Longueur-1. Vous obtiendrez une "exception d'index hors plage" lorsque vous évaluez individuellement [longueur_individuelle]. par exemple. Si la longueur du tableau est 1 alors le seul élément est foo [0], et foo [1] n'existe pas. –

2

Vous pourrait écrire quelque chose de similaire avec LINQ, mais puisque « Zip » n'est pas construit jusqu'à ce que .NET 4.0 il sera plus de code que nous avions comme, et/ou pas aussi efficace. Je serais tenté de le laisser "tel quel", mais je vérifierais probablement target.Length pour éviter une exception hors de portée.

Peut-être que je ferais une méthode d'extension, si:

public static int CompareFitness(this string individual, string target) 
{ 
    int sum = 0, len = individual.Length < target.Length 
     ? individual.Length : target.Length; 
    for (int i = 0; i < len; i++) 
     if (individual[i] == target[i]) sum++; 
    return sum; 
} 

Ensuite, vous pouvez utiliser:

string s = "abcd"; 
int i = s.CompareFitness("adc"); // 2 
+0

D'accord sur le contrôle de longueur. Comment c'est lié à Zip? –

+1

Zip prend deux séquences et les regroupe terme par terme ...? –

+0

D'accord, Marc, mais j'accepte la réponse de Mehrdad parce que je voulais voir comment cela se ferait dans LINQ. Voté pour votre réponse, aussi. Merci! –

-1

Que diriez-vous d'une jointure, ou ai-je mal compris?

static void Main(string[] args) 
    { 
     var s1 = "abcde"; 
     var s2 = "hycdh"; 
     var count = s1.Join(s2, c => c, c => c, (a,b) => a).Count(); 
     Console.WriteLine(count); 
     Console.ReadKey(); 
    } 
+1

Maintenant comparer "ababa" à "babab" - devrait être zéro, mais renvoie 12 ;-p –

+3

Erk. Je devrais probablement supprimer pour éviter downmark ... – spender

+2

Aww. Je pensais que je le laisserais comme exemple de diff entre zip et join. – spender

0

La réponse actuellement sélectionnée ne gère pas correctement les différentes chaînes de longueur. Il ne compare qu'une sous-chaîne maximale des chaînes d'entrée si les longueurs diffèrent.

Par exemple:

Fitness("ABC", "ABC") -> 3 
Fitness("ABC", "ABC this is an 'unfit' string") -> 3 

Ceci peut être facilement fixé en soustrayant les longueurs différentes de votre score. L'amélioration:

return Enumerable.Range(0, Math.Min(individual.Length, target.Length)) 
       .Count(i => individual[i] == target[i]) 
       - Math.Abs(individual.Length - target.Length); 

maintenant:

Fitness("ABC", "ABC") -> 3 
Fitness("ABC", "ABC this is an 'unfit' string") -> -23 

Techniquement, il y a 23 caractères différence entre ces deux entrées.

Questions connexes