2016-12-19 1 views
1

Voici un quiz auto-pensé très semblable à un problème de la vie réelle que je suis confronté. Disons que j'ai une liste de chaînes (disons stringlist), et parmi elles certaines ont des nombres à deux chiffres attachés à la fin. Par exemple, "foo", "foo01", "foo24".Quel est le moyen le plus efficace de filtrer une chaîne avec des nombres à la fin (par exemple, foo12)?

Je veux regrouper ceux avec les mêmes lettres (mais avec des nombres à deux chiffres différents à la fin). Donc, "foo", "foo01", et "foo24" seraient dans le groupe "foo".

Cependant, je ne peux pas vérifier n'importe quelle chaîne commençant par "foo", parce que nous pouvons aussi avoir "food", "food08", "food42".

Il n'y a pas de doublons.

Il est possible d'avoir des nombres au milieu. Ex) "foo543food43" est sous le groupe "foo543food"

Ou même plusieurs numéros à la fin. Ex) "foo1234" est sous le groupe "foo12"

La solution la plus évidente que je peux penser est d'avoir une liste de nombres.

numbers = ["0", "1", "2", ... "9"] 

Ensuite, je ferais

grouplist = [[]] //Of the form: [[group_name1, word_index1, word_index2, ...], [group_name2, ...]] 
for(word_index=0; word_index < len(stringlist); word_index++) //loop through stringlist 
    for(char_index=0; char_index < len(stringlist[word_index]); char_index++) //loop through the word 
     if(char_index == len(stringlist[word_index])-1) //Reached the end 
      for(number1 in numbers) 
       if(char_index == number1) //Found a number at the end 
        for(number2 in numbers) 
         if(char_index-1 == number2) //Found another number one before the end 
          group_name = stringlist[word_index].substring(0,char_index-1) 
          for(group_element in grouplist) 
           if(group_element[0] == group_name) //Does that group name exist already? If so, add the index to the end. If not, add the group name and the index. 
            group_element.append(word_index) 
           else 
            group_element.append([stringlist[word_index].substring(0,char_index-1), word_index]) 
        break //If you found the first number, stop looping through numbers 
          break //If you found the second number, stop looping through numbers 

Maintenant, cela semble désordonnée comme l'enfer. Une façon plus propre à laquelle vous pouvez penser? L'une des structures de données, y compris le résultat final, peut être ce que vous voulez qu'elle soit.

+0

je lirais plus sur [expressions régulières] (https://en.wikipedia.org/wiki/Regular_expression) et comment ils peuvent être convertis en [machines à états finis] (https: //en.wikipedia.org/wiki/Finite-state_machine). Lisez aussi à propos de [l'analyse lexicale] (https://en.wikipedia.org/wiki/Lexical_analysis) & [parsing] (https://en.wikipedia.org/wiki/Parsing). –

Répondre

1

Je voudrais créer une carte qui mappe le nom de groupe à une liste de toutes les chaînes du groupe correspondant.

Voici mon approche en java:

public Map<String, List<String>> createGroupMap(Lust<String> listOfAllStrings){ 
    Map<String, List<String>> result= new Hashmap<>(); 
    for(String s: listOfAllStrings){ 
    addToMap(result, s) 
    } 
} 

private addToMap(Map<String, List<String>> map, String s){ 
    String group=getGroupName(s); 
    if(!map.containsKey(group)) 
    map.put(group,new ArrayList<String>(); 
    map.get(group).add(s); 
} 

private String getGroupName(String s){ 
    return s.replaceFirst("\\d+$", ""); 
} 

Peut-être que vous pouvez gagner un peu de vitesse en évitant la RegExp dans getGroupName(..) mais vous devez le profil pour être sûr qu'une mise en œuvre sans RegExp serait plus rapide.

+0

C'est ce que je voulais (sauf que l'expression régulière est légèrement différente de ce que je demandais, mais c'est trivial). Quelqu'un peut-il m'aider à expliquer la différence de complexité entre cette réponse et ma réponse «juste tout boucle»? – CuriousKimchi

0

Vous pouvez diviser la chaîne en 2 parties comme celle-ci.

pair<string, int> divide(string s) { 
int r = 0; 
if(isdigit(s.back())) { 
    r = s.back() - '0'; 
    s.pop_back(); 
    if(isdigit(s.back())) { 
     r += 10 * (s.back() - '0'); 
     s.pop_back(); 
    } 
} 
return {s, r} 

}