2010-07-15 6 views
1

Ce que j'ai est une zone de texte dans laquelle l'utilisateur tape une chaîne. La chaîne ressemblera à quelque chose comme ceci: G32:04:20:40Trier les résultats de la recherche du fichier texte dans la liste

Ensuite, l'utilisateur appuie sur le bouton de recherche. Le programme doit ensuite ouvrir un fichier texte et rechercher les cinq chaînes les plus proches de celle entrée et les afficher dans une liste.

Je vais définir autant que possible la "chaîne la plus proche" (probablement en utilisant un très long exemple compliqué).

Les données contenues dans le fichier texte ressemble à ceci:

G32:63:58:11 JG01 
G32:86:98:30 JG01 
G33:50:05:11 JG06 
G33:03:84:12 JG05 
G34:45:58:11 JG07 
G35:45:20:41 JG01 
G35:58:20:21 JG03 

Donc, si les types d'utilisateur dans la chaîne:

G33:89:03:20

Les cinq résultats les plus proches devraient afficher dans la zone de liste comme ceci:

G33:50:05:11 JG06 
G33:03:84:12 JG05 
G32:86:98:30 JG01 
G32:63:58:11 JG01 
G34:45:58:11 JG07 

Je devrais probablement poi A ce stade, les chaînes sont des coordonnées et la valeur après "JG" représente la valeur de quelque chose à cette coordonnée.

La façon dont je suis arrivé à ces 5 est en passant par la chaîne morceau par morceau. Donc, l'utilisateur a tapé "G33" donc je trouve tous ceux avec G33 au début - s'il n'y en a aucun, alors je trouve le plus proche de G33. Ensuite, c'était "89" donc je trouve tous ceux où la partie suivante est "89" s'il n'y en a pas, alors le plus proche de 89 le meilleur et ainsi de suite.

Ce que je dois savoir est comment je vais faire ceci? J'ai construit les composants visuels et j'ai aussi un code en place qui traite des choses similaires, mais quand il s'agit de cela, je suis vraiment perplexe. Comme vous pouvez le dire maintenant, je suis plutôt nouveau pour C#, mais j'apprends :)

EDIT: Recherche code

private void btnSearch_Click(object sender, EventArgs e) 
     { 
      lstResult.Items.Clear(); 

      if (txtSearch.Text == String.Empty) 
      { 
       MessageBox.Show("The textbox is empty, there is nothing to search.", 
        "Textbox empty", MessageBoxButtons.OK, MessageBoxIcon.Information); 
      } 
      else 
      { 
       this.CheckFormatting(); 
      } 

     } 

     private long GetIndexForCoord(string coord) 
     { 
      // gets out a numerical value for each coordinate to make it easier to compare 
      Regex m_regex = new Regex("\\d\\d:\\d\\d:\\d\\d:\\d\\d"); 
      string cleaned = m_regex.Match(coord).Value; 
      cleaned = cleaned.Replace(':', '0'); 
      return Convert.ToInt64(cleaned); 
     } 

     private List<string> GetResults(string coord) 
     { 
      // gets out the 5 closest coordinates 
      long index = GetIndexForCoord(coord); 

      // First find the 5 closest indexes to the one we're looking for 
      List<long> found = new List<long>(); 
      while (found.Count < 5) 
      { 
       long closest = long.MaxValue; 
       long closestAbs = long.MaxValue; 
       foreach (long i in m_indexes) 
       { 
        if (!found.Contains(i)) 
        { 
         long absIndex = Math.Abs(index - i); 
         if (absIndex < closestAbs) 
         { 
          closest = i; 
          closestAbs = absIndex; 
         } 
        } 
       } 
       if (closest != long.MaxValue) 
       { 
        found.Add(closest); 
       } 
      } 

      // Then use those indexes to get the coordinates from the dictionary 
      List<string> s = new List<string>(); 
      foreach (long i in found) 
      { 
       s.Add(m_dic[i]); 
      } 
      return s; 
     } 

     private void CheckFormatting() 
     { 
      StringReader objReader = new StringReader(txtSearch.Text); 

      bool FlagCheck = true; 

       if (!Regex.IsMatch(txtSearch.Text, 
        "G3[0-9]{1}:[0-9]{2}:[0-9]{2}:[0-9]{2}")) 
       { 
        FlagCheck = false; 
       } 

      if (FlagCheck == true) 
      { 
       this.CheckAndPopulate(); 
      } 
      else 
      { 
       MessageBox.Show("Your search coordinates are not formatted correctly.", 
         "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); 
      } 
     } 

     private void CheckAndPopulate() 
     { 
      StreamReader objReader = new StreamReader("Jumpgate List.JG"); 
      List<String> v = new List<String>(); 
      do 
      { 
       v.Add(objReader.ReadLine()); 
      } 
      while (objReader.Peek() != -1); 

      objReader.Close(); 

      foreach (string c in v) 
      { 
       long index = GetIndexForCoord(c); 
       m_dic.Add(index, c); 
       m_indexes.Add(index); 
      } 

      List<string> results = GetResults(txtSearch.Text); 
      foreach (string c in results) 
      { 
       lstResult.Items.Add(c); 
      } 
     } 

Répondre

3

Edit: Ajout suggéré de lire le code dans le fichier. Et aussi une explication à la fin.
Edit2: Ajouté si vous vérifiez l'ajout au dictionnaire/liste pour gérer les doublons.

Veuillez noter que ce code est presque certainement inefficace (sauf peut-être par accident) et qu'il doit être nettoyé et que le traitement des erreurs doit être ajouté, mais il peut servir de point de départ pour l'écriture d'un meilleur code. moins. Vous voulez probablement jeter un oeil à k-nearest neighbor algorithm pour trouver la bonne façon de le faire.

J'ai supposé que la lettre au début est toujours G et que les 4 parties des coordonnées sont toujours à 2 chiffres chacune.

Ajoutez les lignes suivantes 2 à votre classe/forme:

Dictionary<long, string> m_dic = new Dictionary<long, string>(); 
    List<long> m_indexes = new List<long>(); 

les initialiser ensuite avec le code suivant (je l'ai supposé que vous avez déjà lu dans toutes les coordonnées dans un tableau de chaînes appelé v avec un coordonnées par article):

foreach (string c in v) 
{ 
    long index = GetIndexForCoord(c); 
    if(!m_dic.ContainsKey(index)) 
    { 
     m_dic.Add(index, c); 
     m_indexes.Add(index); 
    } 
} 

ajouter ensuite les 2 méthodes suivantes:

// gets out a numerical value for each coordinate to make it easier to compare 
private long GetIndexForCoord(string coord) 
{ 
    Regex m_regex = new Regex("\\d\\d:\\d\\d:\\d\\d:\\d\\d"); 
    string cleaned = m_regex.Match(coord).Value; 
    cleaned = cleaned.Replace(':', '0'); 
    return Convert.ToInt64(cleaned); 
} 
// gets out the 5 closest coordinates 
private List<string> GetResults(string coord) 
{ 
    long index = GetIndexForCoord(coord); 

    // First find the 5 closest indexes to the one we're looking for 
    List<long> found = new List<long>(); 
    while (found.Count < 5) 
    { 
      long closest = long.MaxValue; 
      long closestAbs = long.MaxValue; 
      foreach (long i in m_indexes) 
      { 
       if (!found.Contains(i)) 
       { 
        long absIndex = Math.Abs(index - i); 
        if (absIndex < closestAbs) 
        { 
         closest = i; 
         closestAbs = absIndex; 
        } 
       } 
      } 
      if (closest != long.MaxValue) 
      { 
       found.Add(closest); 
      } 
    } 

    // Then use those indexes to get the coordinates from the dictionary 
    List<string> s = new List<string>(); 
    foreach (long i in found) 
    { 
     s.Add(m_dic[i]); 
    } 
    return s; 
} 

Enfin lorsque l'utilisateur d'entrer les données que vous envoyez ces données à la méthode que:

List<string> results = GetResults(lookingFor); 

Vous pouvez ensuite utiliser les résultats pour remplir votre zone de liste.

Le code fonctionne en convertissant chaque coordonnée en une valeur numérique appelée index (car il est plus facile de travailler avec) et il ajoute ensuite toutes les coordonnées à un dictionnaire avec l'index comme clé.
Lorsqu'il regarde les coordonnées les plus proches, il compare la différence de valeur entre l'index que vous recherchez et chacun des index précédemment stockés pour trouver les 5 plus proches (il utilise la méthode Math.Abs pour pouvoir faire la différence sans avoir à s'inquiéter des nombres négatifs). C'est assez inefficace car il boucle chaque valeur une fois pour chaque coordonnée que vous voulez trouver (donc si votre liste contient 1000 coordonnées et que vous voulez trouver les 5 plus proches, elle passera par la boucle interne 5000 fois, je suppose que pourrait probablement être réduit à seulement 1000 fois en améliorant le code, je suggère de regarder le lien wiki près du haut de cette réponse pour un meilleur algorithme).

+0

points pour l'utilité. Je vais voir si je peux transformer cela en C# (ça me ressemble VB.NET). Je vais aussi regarder le lien que vous avez posté. Merci – Arcadian

+0

@ Arcadian: Désolé à ce sujet, je ne sais pas pourquoi je pensais que vous vouliez dans VB, devrait être mieux maintenant si. –

+0

lol np, j'ai déjà utilisé VB, merci de l'avoir changé. – Arcadian