Question

J'ai un script qui boucle une série de quatre (ou moins) chaînes de caractères. Par exemple:

aaaa
aaab
aaac
aaad

Si ont été en mesure de mettre en œuvre avec des boucles imbriquées comme ceci:

chars = string.digits + string.uppercase + string.lowercase

for a in chars:
    print '%s' % a   
    for b in chars:
        print '%s%s' % (a, b)
        for c in chars:
            print '%s%s%s' % (a, b, c)
            for d in chars:
                print '%s%s%s%s' % (a, b, c, d)

est ce genre de boucle nichant une mauvaise chose, et si oui, quelle serait une meilleure façon d'accomplir ce que je fais?

Était-ce utile?

La solution

import string
import itertools

chars = string.digits + string.letters
MAX_CHARS = 4
for nletters in range(MAX_CHARS):
    for word in itertools.product(chars, repeat=nletters + 1):
        print (''.join(word))

Ce imprimerons tous les 15018570 mots que vous recherchez. Si vous voulez plus / moins de mots changent simplement la variable MAX_CHARS. Il aura encore seulement deux s pour tout for nombre de caractères, et vous ne devez pas vous répéter. Et est assez lisible. .

Autres conseils

Je vais soumettre ma réponse comme le plus lisible et moins évolutive:)

import string
chars = [''] + list(string.lowercase)

strings = (a+b+c+d for a in chars
                   for b in chars
                   for c in chars
                   for d in chars)

for string in strings:
    print string

EDIT: En fait, ce qui est faux, car il produira des copies de toutes les chaînes de longueur <4. Retrait de la chaîne vide de la gamme chars serait tout simplement produire des chaînes de 4 caractères.

Normalement, je supprime cette réponse, mais je reste un peu comme si vous avez besoin de générer des chaînes de la même longueur.

Ecrire pour le programmeur premier -. Le second ordinateur
S'il est clair et évident de comprendre alors son correcte.

Si les questions de vitesse et le compilateur ne permet pas d'optimiser toute façon et si vous mesurez et il est le problème - alors penser à une façon plus rapide intelligent

Je ne pense pas que ce soit une mauvaise chose, à condition que vous comprenez (et le document :-) il. Je ne doute pas qu'il peut y avoir une façon ou d'une solution plus intelligente pythonique (avec lambdas ou autres joyeusetés) mais je l'ai toujours privilégié la lisibilité sur l'intelligence.

Puisque vous devez générer toutes les possibilités de 1, 2, 3 et 4 caractères « mots », cette méthode est aussi bon que. Je ne sais pas combien de temps cela prendrait puisque vous générer efficacement (très approximativement) 14 millions de lignes de sortie (mais probablement toute solution aurait ce problème).

Pré-calcul des préfixes communs peuvent donner un coup de pouce de la vitesse, mais vous seriez mieux mesurer pour vérifier ( toujours vérifier, jamais supposer):

chars = string.digits + string.uppercase + string.lowercase
for a in chars:
    print a
    for b in chars:
        ab = '%s%s' % (a, b)
        print ab
        for c in chars:
            abc = '%s%s' % (ab, c)
            print abc
            for d in chars:
                print '%s%s' % (abc, d)

EDIT: En fait, je l'ai fait quelques points de référence (avec Windows Python 2.6.1) - cette version prend environ 2,25 unités de temps par rapport à la 2.84 il est donc 26% plus rapide d'origine. Je pense que cela pourrait justifier son utilisation (encore une fois, tant qu'il est documenté clairement ce qu'il tente d'accomplir).

Il ne répond pas exactement à la question, mais cela retournerait la combinaison pour la th n longueur maximale et des caractères donnés dans l'alphabet à utiliser:

#!/usr/bin/python

def nth_combination(n, maxlen=4, alphabet='abc'):
    """
    >>> print ','.join(nth_combination(n, 1, 'abc') for n in range(3))
    a,b,c
    >>> print ','.join(nth_combination(n, 2, 'abc') for n in range(12))
    a,aa,ab,ac,b,ba,bb,bc,c,ca,cb,cc
    >>> import string ; alphabet = string.ascii_letters + string.digits
    >>> print ','.join(nth_combination(n, 4, alphabet) for n in range(16))
    a,aa,aaa,aaaa,aaab,aaac,aaad,aaae,aaaf,aaag,aaah,aaai,aaaj,aaak,aaal,aaam
    >>> print ','.join(nth_combination(n, 4, alphabet)
    ...                for n in range(0, 14000000, 10**6))
    a,emiL,iyro,mKz2,qWIF,u8Ri,zk0U,Dxav,HJi9,LVrM,P7Ap,UjJ1,YvSE,2H1h
    """
    if maxlen == 1:
        return alphabet[n]
    offset, next_n = divmod(n, 1 + len(alphabet)**(maxlen-1))
    if next_n == 0:
        return alphabet[offset]
    return alphabet[offset] + nth_combination(next_n-1, maxlen-1, alphabet)

if __name__ == '__main__':
    from doctest import testmod
    testmod()

Bien sûr, cela n'a de sens que si vous avez besoin d'un accès aléatoire à l'ensemble des combinaisons au lieu de itérer toujours par tous.

Si est élevé maxlen, certains pourraient être atteint optimisation de la vitesse par exemple en se débarrassant de concaténation de chaînes et de re-calcul de la longueur de et alphabet à chaque niveau maxlen-1 de la récursion. Une approche non récurrente pourrait donner un sens aussi.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top