7
votes

Combien de mots anglais communs de 4 lettres ou plus pouvez-vous faire à partir des lettres d'un mot donné (chaque lettre ne peut être utilisée qu'une fois)

à l'arrière d'un calendrier de bloc, j'ai trouvé l'énigme suivante:

Combien de mots anglais communs de 4 lettres ou plus pouvez-vous faire des lettres du mot "manuel" (chaque lettre ne peut être utilisée qu'une seule fois).

Ma première solution que j'ai proposée était: xxx

ceci donne le résultat défini (["Tote", "goûte", 'Text', 'Boot', 'A pris', 'Toot', 'Book', 'TOKE', 'TOKE', 'BETOOK'])

Ma prochaine itération était: xxx

qui retourne une réponse presque immédiatement mais donnait comme réponse: ['book', 'goûte', 'toot', 'toot' ]

Quelle est la solution la plus rapide, correcte et la plus pythonique à ce problème?

( edit : ajouté ma solution de permutations antérieure et sa Différente sortie).


4 commentaires

Supprimé ma réponse avant de voir votre commentaire, pour la même raison que vous avez souligné. Merci


Vous pouvez résoudre celui-ci extrêmement efficace avec un pré-traitement de la plume et l'attribution de chaque lettre une représentation principale. Je vais écrire une solution si j'ai le temps plus tard.


@Voo, je vais attendre avec le choix d'une réponse correcte jusqu'à ce que vous ayez soumis votre solution. Je suis impatient d'y être.


Cette question semble être hors sujets car il s'agit de puzzles de programmation ( codegolf.stackexchange.com )


6 Réponses :


2
votes

Il y a un générateur itheroTools.permutations code> avec lequel vous pouvez rassembler toutes les permutations d'une séquence avec une longueur spécifiée. Cela facilite la tâche: xxx pré>

édition # 1: Oh! Il dit "4 ou plus";) oublie ce que j'ai dit! P>

Edit # 2: Ceci est la deuxième version que j'ai proposée: p>

LETTERS = set('textbook')

with open('/usr/share/dict/words') as f:
    WORDS = filter(lambda x: len(x) >= 4, [l.strip() for l in f])

matching = filter(lambda x: set(x).issubset(LETTERS) and all([x.count(c) == 1 for c in x]), WORDS)
print len(matching)


5 commentaires

Je n'ai pas creusé cela beaucoup, mais ce code me donne des résultats différents et prend plus de 20 fois plus longtemps pour exécuter.


Veuillez également noter que ma version se souciait de chaque mot correspondant contenant chaque lettre une seule fois.


Votre deuxième version ne renvoie que des mots dans lesquels chaque lettre est différente (dans ce cas: TOKE ), mais Tote , oboe , texte < / code>, boot , a pris , toot , book et betook sont Aussi des solutions valides.


Citation: "Chaque lettre ne peut être utilisée qu'une seule fois". ;)


@Gandaro bien mais il y a deux t s dans le manuel et chacun peut être utilisé une fois;)



3
votes

On dirige-t-il?

>>> print matches
set(['textbook', 'keto', 'obex', 'tote', 'oboe', 'text', 'boot', 'toto', 'took', 'koto', 'bott', 'tobe', 'boke', 'toot', 'book', 'bote', 'otto', 'toke', 'toko', 'oket'])


0 commentaires

2
votes

Créez l'ensemble de la puissance, puis vérifiez si le mot dictionnaire est dans l'ensemble (l'ordre des lettres n'a pas d'importance):

powerset = lambda x: powerset(x[1:]) + [x[:1] + y for y in powerset(x[1:])] if x else [x]

pw = map(lambda x: sorted(x), powerset(given_word))
filter(lambda x: sorted(x) in pw, words)


1 commentaires

Cool, je n'avais pas déjà entendu parler du concept de Powerset. Petit Nitpick, votre mise en œuvre actuelle ne filtre pas les mots de Lengt 4 ou plus.



3
votes

Je pensais partager cette astuce légèrement intéressante bien que cela prend un bon plus de code que le reste et n'est pas vraiment "Pythonic". Cela prendra un bon plus de code que les autres solutions mais devraient être assez rapides si je regarde le timing des autres besoin.

Nous faisons un peu de prétraitement pour accélérer les calculs. L'approche de base est la suivante: nous attribuons chaque lettre de l'alphabet un nombre premier. Par exemple. A = 2, B = 3, et ainsi de suite. Nous calculons ensuite un hash pour chaque mot dans l'alphabet qui est simplement le produit des représentations premières de chaque personnage dans le mot. Nous stockons ensuite chaque mot dans un dictionnaire indexé par le hachage.

Maintenant si nous voulons savoir quels mots sont équivalents à dire manuel nous ne devons calculer que le même hachage pour le mot et le regarder dans notre dictionnaire. Habituellement (par exemple en C ++), nous devions nous inquiéter des débordements, mais en Python, il est encore plus simple que cela: chaque mot de la liste avec le même index contiendra exactement les mêmes caractères.

Voici le code Avec une légère optimisation que, dans notre cas, nous n'avions à vous inquiéter qu'aux personnages apparaissant également dans le mot donné, ce qui signifie que nous pouvons obtenir avec une table de choix beaucoup plus petite que sinon (l'optimisation évidente serait de ne céder que des caractères apparaissant dans le Word une valeur du tout - il était assez rapide de toute façon, je ne me suis donc pas dérangé et de cette façon, nous ne pouvions pas traiter une seule fois et le faire pour plusieurs mots). L'algorithme de choix est utile assez souvent pour que vous puissiez en avoir une vous-même;) xxx

fonctionne sur ma liste de mots Ubuntu (mots de 98k) plutôt rapidement, mais pas ce que je Appelez Pythonic car il s'agit essentiellement d'un port d'un algorithme C ++. Utile si vous voulez comparer plus d'un mot de cette façon ..


2 commentaires

Explication et code très clairs, merci. Votre code a également été renvoyé les mots corrects kobe , otto et too et maintenant je me demande pourquoi ma solution de permutations n'a pas présenté à celles-ci.


@Biogeek, vous ne gérez pas de majuscules / minuscules de manière équivalente.



2
votes

Ce qui suit vérifie simplement chaque mot dans le dictionnaire pour voir si elle est de la longueur appropriée, puis s'il s'agit d'une permutation de «manuel». J'ai emprunté le chèque de permutation de Vérification si deux chaînes sont des permutations les unes des autres dans Python mais a légèrement changé.

given_word = 'textbook'

with open('/usr/share/dict/words', 'r') as f:
    words = [s.strip() for s in f.readlines()]

matches = []
for word in words:
    if word != given_word and 4 <= len(word) <= len(given_word):
        if all(word.count(char) <= given_word.count(char) for char in word):
            matches.append(word)
print sorted(matches)


6 commentaires

Pas de Lambda, pas de carte, aucun filtre: enfin, Ceci est pythonique. Bien que l'utilisation des compréhensions de générateur au lieu d'une compréhension de la liste et une boucle d'accumulation devait être plus efficace.


@Evpok Je peux comprendre (et accepter) Pourquoi la carte et le filtre ne seraient pas nécessaires avec des compromies de la liste, mais je ne vois pas pourquoi créer des dizaines de mini-fonctions serait particulièrement pythonique au lieu d'utiliser des Lambdas?


Voir Réponse de Guido : "[...] une fois que la carte (), filtre () et réduire () sont partis, il n'y a pas beaucoup d'endroits où vous avez vraiment besoin d'écrire des fonctions locales très courtes [...] ». Pourquoi auriez-vous besoin de Lambdas si vous utilisez des compréhensions?


@Evpok pas pour les générateurs évidemment, mais pour beaucoup d'autres situations. Passer des fonctions triviales (par exemple des comparateurs) est souvent utile (fondamentalement, tout type de rappel) peut également être une caractéristique immensément utile de mon expérience. Mais dépend certainement du style de codage.


@Voo a accepté des comparateurs, j'adore vraiment le style de codage fonctionnel et je abuse régulièrement functools.Partial . Mais Python n'était pas censé être une langue fonctionnelle.


@Evpok: Un peu hors sujet ici, mais s'il vous plaît, seriez-vous assez gentille pour considérer ce post ? Merci d'avance.



1
votes

Les permutations sont très grandes pour des mots plus longs. Essayez contrevolutaire par exemple.

Je filtrerais la dicte pour les mots de 4 à Len (mot) (8 pour manuel). Ensuite, je filtrerais avec une expression régulière "hautbois" .matches ("[manuel] +").

Les mots restants, je trierais et comparez-les avec une version triée de votre mot, ("beoo", "bekoottx") avec un saut à l'index suivant d'un caractère correspondant, pour trouver des numéros de déséquilibre. des caractères: xxx

puisque je ne parle pas python, je laisse la mise en œuvre comme un exercice au public.


0 commentaires