7
votes

Comment comparer 2 matrices de chaîne et trouver toutes les correspondances consécutives et économisez des indices?

Par exemple, si j'ai les 2 tableaux suivants:

int[] match0 = new int[] {0, 1, 2}; // indices for "the quick brown"
int[] match2 = new int[] {4, 5}; // indices for "jumps over"
int[] match1 = new int[] {3}; // index for "dog"


6 commentaires

Quelque chose t'a essayé? Cela ne semble pas trop compliqué.


J'ai essayé un peu, ce n'est pas aussi facile que je pensais que ce serait, car certains mots peuvent être utilisés plus d'une fois et je cherche les plus longs matchs consécutifs. Par exemple, dans ce qui précède, "le" peut être dans la phrase deux fois et les deux devraient être vérifiés.


Cela ressemble à une légère variante de: en.wikipedia.org/wiki/longest_common_substring_problem . Vous pouvez convertir votre tableau en une chaîne délimitée et utiliser les algorithmes résolvant ce problème pour résoudre votre problème. Je déduit de vos commentaires que vous essayez vraiment d'essayer de trouver le plus long, et non de toutes les combinaisons de matchs, même si votre question est de savoir comment votre question se lit comme suit: BTW Il y a une implémentation déjà affichée pour C # sur la pile déjà: Stackoverflow.com/questions/4597010/longest-common-sUtiliseren CE


Pas seulement le plus long. Je veux toutes les combinaisons, mais seulement les plus longues sans mots qui se chevauchent sur la première matrice.


C'est donc le deuxième "le" un match ou n'est pas? Puisqu'il ne se chevauche pas.


Pouvez-vous fournir plus de détails? Dans l'exemple ci-dessus, le tableau de l'utilisateurLect n'a qu'une seule instance de "the" donc peu importe.


5 Réponses :


1
votes

Cela ne fait pas exactement ce que vous voudriez, mais c'est un moyen très propre et simple d'obtenir un nouveau tableau avec toutes les chaînes communes (c.-à-d. Prendre l'intersection des deux tableaux).

var results = array1.Intersect(array2, StringComparer.OrdinalIgnoreCase);


3 commentaires

Cela n'aide pas, car toutes les valeurs du tableau de l'utilisateurLect seront toujours renvoyées à chaque fois sur votre code dans tous mes exemples.


@rotaraercz je ne comprends pas vraiment ce que vous dites. Ce n'est pas la façon dont l'intersection fonctionne. Si je croise les matrices suivantes; {1, 2, 4, 7} et {2, 7, 9, 10, 11} Le résultat serait {2, 7} . Votre deuxième bloc de code n'a aucun sens. Il est fort de coder les index de l'intersection de la matrice source et des cordes dans le commentaire. Pourquoi prendre les index quand vous pouvez prendre les éléments eux-mêmes?


Le deuxième bloc de code correspond aux résultats que je veux, qui sont une liste de tableaux avec les valeurs d'index du tableau d'utilisateursélect enregistré. Je cherche les plus longs matchs consécutifs. Par exemple: {A, B, D, G} et {B, D, G, Y, Z} aurait: {1, 2, 3} Parce que B, D, G sont dans les index 1, 2, 3 du premier tableau.



2
votes

Voici ce que je suis venu avec xxx

ceci produira xxx

à l'aide de l'entrée {"Le" "," rapide "," marron "," the "," paresseux "," chien "} rendements: xxx

Notez que les appels vers TOARRAY < / code> sont facultatifs. Si vous n'avez pas besoin de recevoir les résultats dans un tableau, vous pouvez laisser cela et enregistrer un peu de temps de traitement.

Pour filtrer toutes les séquences complètement contenues avec d'autres plus grandes Séquences, vous pouvez exécuter ce code (notez le chy dans la requête modifiée): xxx


19 commentaires

Cela fonctionnera-t-il à droite si les utilisateursElect sont {"le", "rapide", "brun", "le", "paresseux", "chien"} ?


Dans ce cas, il génère {{0}, {3}, {1, 2}, {0}, {3, 4, 5}} . Quelle serait la sortie souhaitée?


Je m'attendrais, basé sur la description de l'OP, {{0, 1, 2}, {3, 4, 5}} '


La sortie de Jim Mischel est la sortie correcte que j'essaie d'atteindre.


@ROTAERCZ Retour à la planche à dessin, je suppose. Donnez-moi un peu de temps pour y travailler.


Je suis définitivement intéressé à voir une solution LINQ. Je suis toujours étonné de ce que Linq peut faire.


@rotaerercz Voir ma réponse mise à jour. Il ne filtre toujours pas de séquences qui se chevauchent, mais il se rapproche de plus près. Que doit être le résultat attendu si l'entrée est {"le", "rapide", "brun", "rapide", "brun", "renard"} ?


Oui, c'est vraiment proche.


@rotaerercz Voir ma mise à jour pour filtrer les sous-séquences contenues. Ce n'est pas joli (et je ne l'utiliserais pas pour d'énormes séquences) mais ça marche!


Je l'essais. Je pense que le filtre peut avoir un bug? J'ai essayé ce qui suit ... UtilisateursElect: {"Le" conducteur "," était "," surpris ","; "", "The", "Slabed", "." } Original: {"Le" conducteur "," était "", "surpris", "," "aussi", ";" "," The "", ",", "," ",". " }


Les résultats que j'ai reçus étaient {{0, 1, 2, 3}, {4, 5, 6}, {7, 8} qui correspond à " le pilote a été surpris "," ; le traîneau "et" déplacé. ". Ça a l'air correct pour moi. Quel devrait être le résultat?


Vous avez raison, ça fonctionne correctement! Ma boucle à la console était incorrecte.


J'ai trouvé un nouveau bogue. Pourriez-vous le réparer? J'ai essayé ce qui suit ... UtilisateursElect: {"Le", "traîneau", "avait" "," pas "," déplacé ","; "", "Le" conducteur "," était surpris "," "."} Original: {"Le" conducteur "," était "," surpris ",", "", "aussi", ";", ",", "," , "déplacé", "."} j'ai eu: {{0,1,2,3,4}, {6,7,8,9}, {5,6}, {10}}. Remarquez le chevauchement de 6.


Dans ce scénario, il devrait retourner: {{0,1,2,3,4}, {5,6}, {7,8,9}, {10}}


@rotaerercz qui était en quelque sorte par conception. Je n'ai que filtré uniquement des listes qui étaient complètement contenues dans (sous-ensembles de) listes plus grandes. Ici l'élément 6 apparaît dans une liste plus grande mais 5 ne le fait pas, il ne sera donc pas exclu. Cependant, vous pouvez facilement modifier le tout dans mon code de filtrage sur tout pour filtrer les chevauchements. Je pense que cette fonction sera moins bien comportée lorsque vous avez deux séquences qui se chevauchent de la même longueur, mais peut-être que cela va bien pour vos besoins.


Oh, tu as déjà répondu! Wow, c'était rapide. En fait, il devrait être: dans ce scénario, il devrait retourner: {{0,1,2,3,4}, {5}, {6}, {7,8,9}, {10}}


Je suis en fait d'accord que la réponse que vous avez fournie pour cette question est optimale. Je vais mettre cela en place comme une nouvelle question. Peut-être aimeriez-vous que ça va? :)


J'ai monté une nouvelle question ici: Stackoverflow.com/Questtions/17235221/...


Désolé pour le retard. Je ne comprends pas pourquoi vous avez dit qu'il devrait renvoyer {{0,1,2,3,4}, {5}, {6}, {7,8,9}, {10}} . Je peux probablement le modifier pour revenir {{0,1,2,3,4}, {5}, {6,7,8,9}, {10}} ou { {0,1,2,3,4}, {5,6}, {7,8,9}, {10}} .



2
votes

Ceci serait plus facile si les mots ne pouvaient pas être répétés. . .

L'idée générale est de créer un dictionnaire > dans la liste des mots d'origine. Cela vous dira quels mots sont utilisés à quels positions. Le dictionnaire pour votre échantillon serait: xxx

Maintenant, lorsque vous obtenez l'entrée de l'utilisateur, vous passez de manière séquentielle, en recherchant les mots de votre dictionnaire pour obtenir la liste de Positions.

Donc, vous recherchez un mot et que c'est dans le dictionnaire. Vous enregistrez la ou les positions renvoyées du dictionnaire. Recherchez le mot suivant. Il y a trois conditions que vous devez gérer:

  1. Le mot n'est pas dans le dictionnaire. Économisez votre groupe consécutif précédent et allez au mot suivant, où vous aurez potentiellement démarrer un nouveau groupe.
  2. Le mot est dans le dictionnaire, mais l'aucune des positions renvoyées correspondent aux positions attendues (les positions attendues étant un de plus que les positions sauvegardées du dernier mot). Enregistrez votre groupe consécutif précédent et allez au mot suivant, où vous aurez potentiellement démarrer un nouveau groupe.
  3. Le mot est dans le dictionnaire et l'une des positions renvoyées correspond à la position attendue. Économisez ces positions et allez au mot suivant.

    J'espère que vous obtenez l'idée.


1 commentaires

C'est très proche de la direction que je pensais aussi. Je viens de faire du mal à le convertir en code.



0
votes

Utilisez LINQ pour plus d'amusement

Après quelques essais, j'ai proposé une solution pure Linq que théoriquement peut être une doublure. J'ai essayé de le rendre efficace, mais bien sûr des solutions fonctionnelles entraînera des calculs en double puisque vous ne pouvez pas garder l'état. P>

Nous commençons par un petit pré-traitement pour économiser des calculs en double. Oui, je sais ce que je fais avec Index est une pratique douteuse, mais si vous faites attention, cela fonctionne et qu'il y arrive rapidement: p> xxx pré>

la monstruosité h2>
.Select(w => Enumerable.Range(w.Start, w.Length).ToArray())


0 commentaires

1
votes

Ce n'est pas très élégant mais efficace. En ce qui concerne les indices LINQ le rend souvent plus compliqué et moins efficace, alors des boucles simples. XXX PRE>

Sortiez les indices des groupes consécutifs + les indices des uniques: P>

var consecutiveGroupsIndices = consecutiveGroups
    .OrderByDescending(kv => kv.Value.Count)
    .Select(kv => Enumerable.Range(kv.Key, kv.Value.Count).ToArray()
    .ToArray());
foreach(var consIndexGroup in consecutiveGroupsIndices)
    Console.WriteLine(string.Join(",", consIndexGroup));
Console.WriteLine(string.Join(",", uniques.Select(u => u.Item1)));


5 commentaires

J'essayais de tester votre réponse mais j'utilise .NET 3.5 pour mon projet Android, je ne peux donc pas utiliser des tuples.


@ROTAERERCZ: Utilisez alors simplement une liste et ajoutez les indices des éléments uniques ou une liste si vous souhaitez voir la chaîne. J'ai utilisé une deuxième collection car les articles uniques n'appartiennent pas aux groupes consécutifs du tout, mais vous souhaitez les voir de toute façon que votre sortie souhaitée suggère.


Est-ce que je viens de remplacer le tuple avec la liste ? Je ne connais pas les objets tuples.


@ROTAERCZ: Non, je présume que vous voulez voir uniquement les indices et les uniques. Ensuite, vous devez utiliser une liste . Donc remplacer ilist > Unique = nouvelle liste > (); avec var niques = nouvelle liste () . Ensuite, remplacez le code one-liner unique.add (tuple.create (i, US)); avec unique.add (i) . Notez que le string.join avec un ienumerable surcharge était également neuf dans .NET 4. Vous devez donc les convertir en une matrice avec TOARRAY < / code>. Par exemple (pour les uniques à la fin): console.writeline (string.join (",", unique.select (i => i.tostring ()). TOARRAY ())); .


Il fournit le même résultat que dans votre question. Les principaux résultats sont dans le dictionnaire où la clé est l'index min de chaque groupe et la valeur est la liste de toutes les chaînes consécutives.