2010-08-20 6 views
8

Je cherche un moyen efficace (en .NET), comment trouver s'il y a une séquence d'octets dans une liste d'octets et s'il y en a, index où le premier commence.Comment trouver l'index de la sous-liste dans la liste?

Par exemple disons que j'ai:

var sequence = new List<byte> { 5, 10, 2 }; 
var listOne = new List<byte> { 1, 3, 10, 5, 10, 2, 8, 9 }; 
var listTwo = new List<byte> { 1, 3, 10, 5, 2, 10, 8, 9 }; 

et le résultat devrait être que ma séquence est l'indice 3 dans le LISTONE et l'indice -1 (.-À-dire qu'il est pas là) dans le listTwo.

Bien sûr, je peux parcourir la liste int par int et depuis chaque index et rechercher si les nombres suivants correspondent à ma séquence, mais y a-t-il un moyen plus efficace (par exemple en utilisant des méthodes d'extension)?

+1

Si la liste n'est pas triée, vous devrez sûrement parcourir tous les éléments jusqu'à ce que la séquence soit trouvée? L'utilisation de méthodes d'extension ou Linq ne peut pas augmenter l'efficacité de façon magique. –

+0

Je doute qu'il y ait une librairie .NET avec ce type d'extension. Mais vous pouvez créer le vôtre. –

+0

Je dois ajouter, que ma séquence est plutôt courte (peu de nombre) mais les listes où je la recherche sont longues (milliers d'articles) –

Répondre

1

Je suggérerais de convertir chaque List<int> en String puis de chercher en utilisant le String.IndexOf(sequence) pour déterminer où ou si la séquence est présente.

+1

Mmh Je doute vraiment que cela augmentera l'efficacité, car vous devez créer des chaînes à partir de listes (avec plus d'utilisation de la mémoire et plus de calculs). Pour sûr, cela facilitera les choses, car vous n'avez pas besoin d'écrire le code pour rechercher la sous-chaîne. – digEmAll

+0

Je suis également préoccupé par l'efficacité. Mais il serait certainement plus court et peut-être lisible. –

+0

Si vous créez une méthode d'extension et la décrivez, elle sera également courte et lisible au lieu d'utilisation. –

5

Ceci est essentiellement le même problème que la recherche de sous-chaîne (en effet, une liste où l'ordre est significatif est une généralisation de "chaîne").

Heureusement, l'informatique a souvent considéré ce problème depuis longtemps, vous permettant ainsi de rester sur les épaules des géants.

Regardez la littérature. Quelques points de départ sont raisonnables:

http://en.wikipedia.org/wiki/Knuth%E2%80%93Morris%E2%80%93Pratt_algorithm

http://en.wikipedia.org/wiki/Boyer%E2%80%93Moore_string_search_algorithm

http://en.wikipedia.org/wiki/Rabin-karp

Même que le pseudo-code dans les articles wikipedia est suffisant pour port C# assez facilement. Regardez les descriptions de performance dans différents cas et décidez quels cas sont les plus susceptibles d'être rencontrés par votre code. (Je pense le premier de ce que vous dites à propos de la liste de clés de recherche étant court).

+0

Merci pour les liens, je me demandais juste, s'il y a une méthode implémentée dans.NET en utilisant certains de ces algorithmes, pour gagner du temps, avant de les implémenter moi-même. –

+0

Il est très probable que 'System.String.IndexOf' implémente l'un d'entre eux! Le fait que vous appliquiez le même algorithme à un type de données n'est pas aussi souvent utilisé car cela réduit vos chances de trouver un impl. Je suis sûr qu'il y en a un là-bas quelque part, mais le trouver est différent. –

4

Je pense que la façon la plus propre est de créer une méthode d'extension générique comme ceci:

public static int SubListIndex<T>(this IList<T> list, int start, IList<T> sublist) 
{ 
    for (int listIndex = start; listIndex < list.Count - sublist.Count + 1; listIndex++) 
    { 
     int count = 0; 
     while (count < sublist.Count && sublist[count].Equals(list[listIndex + count])) 
      count++; 
     if (count == sublist.Count) 
      return listIndex; 
    } 
    return -1; 
} 

pour appeler ainsi:

var indexOne = listOne.SubListIndex(0, sequence); 
var indexTwo = listTwo.SubListIndex(0, sequence); 

post-scriptum vous pouvez également commencer à partir d'un index donné, si vous devez rechercher d'autres occurrences de sous-listes

+0

C'est exactement ce que je fais maintenant. Mais comme l'a déclaré Jon Hanna, il existe des moyens plus efficaces pour la recherche de sous-ensembles. Je veux juste savoir si je ne manque pas quelque chose dans .NET. –

+0

IMO ces algorithmes ne sont pas facilement applicables aux chaînes non-char. Par exemple, boyer-moore nécessite un tableau de taille alphabeth et pour Int32, la taille de l'alphabet est 2^32. Rabin-karp utilise un hachage qui, pour des chaînes non réelles, pourrait être assez difficile à mettre en œuvre. Probablement le seul vraiment utilisable est Knuth-Morris-Pratt, mais je ne pense pas que ce serait plus rapide ... – digEmAll

Questions connexes