1
votes

Trisecter une chaîne

Ecrivez une fonction qui prend une chaîne "s" comme argument et divise s en, et retourne un tuple (gauche, milieu, droite). Si la longueur de la chaîne n'est pas également divisible par trois, votre fonction doit tenter de diviser la chaîne aussi uniformément que possible.

J'ai essayé d'utiliser des boucles for et string replace, des fonctions de strip qui manifestement ne fonctionnaient pas ... Je suis perdu. Le code que j'ai maintenant affiche tout en 3

def trisect(s): 
    print(tuple([s[i:i+3] for i in range(0, len(s), 3)]))
s = input("what is your string: ")
trisect(s)

Résultat attendu: Entrée: "123456789012" Sortie: ('1234', '5678', '9012')

Résultat réel: Entrée: "123456789012" Sortie: ('123', '456', '789', '012')


2 commentaires

Vous n'obtenez actuellement que des chaînes de 3 caractères car vous avez fixé la taille de votre sous-chaîne. s [i: i + 3] sera toujours une sous-chaîne de longueur 3, donc si vous obtenez une chaîne de plus ou moins de 9 caractères, elle échouera.


range (a, b, 3) signifie "divisé en N sous-chaînes séparées de longueur 3"; cela ne signifie pas "divisé en exactement 3 sous-chaînes".


3 Réponses :


0
votes

Vous pouvez obtenir la longueur de la chaîne en utilisant len (s) puis la longueur des sections en utilisant len (s) // 3 ( // effectue une division entière).

À partir de là, découpez simplement comme il convient:

length = len(s) // 3
trisections = s[:length], s[length:length * 2], s[length * 2:]

Modifier:

Utilisez length = rond (len (s) / 3)


3 commentaires

s = "abcdefgh" -> trisections = ('ab', 'cd', 'efgh')


Je pense que ce serait une meilleure idée d'utiliser la division régulière, puis d'arrondir la longueur à l'entier le plus proche. Cela résoudrait le problème signalé par @brentertainer


L'arrondi donne des résultats étranges, comme ('abc', 'de', 'fgh') , mais au moins il résout le problème de différence. La réponse de Brentertainer donne des résultats cohérents.



2
votes

XXX

# The method.
def n_sect(s, n):
    m, r = divmod(len(s), n)
    idx_a = 0
    result = []
    for i in range(n):
        idx_b = idx_a + m + (i < r)
        result.append(s[idx_a:idx_b])
        idx_a = idx_b
    return result

# Try it yourself!
import string
for n in range(3, 5):
    for i in range(1, 27):
        s = string.ascii_lowercase[:i]
        print(n_sect(s, n))
    print()

EDIT: Une approche généralisée.

('ab', 'cd', 'ef')
('ab', 'cd', 'efg')
('ab', 'cde', 'fgh')


2 commentaires

Fonctionne bien sur 3 mais je souhaite que cela soit généralisé à tout n (joli bonus!). En outre, ce serait un peu plus intuitif s'il était rembourré pour s'adapter à l'avant plutôt qu'à l'arrière. +1 de toute façon.


Ah, tout comme j'en avais posté un. Bon travail cependant, j'aime ça.



1
votes

Au départ, je pensais que c'était un doublon, mais les threads existants ne semblent pas prendre en compte l'exigence "aussi uniformément que possible". L'utilisation de textwrap.wrap , zip et la plupart des solutions itertools laissent un morceau inégal à la fin. Cette solution segmente les valeurs arbitraires de n et remplit par l'avant.

L'approche consiste à prendre le quotient et le reste de la longueur de l'itérable et à commencer l'itération par la taille de bloc souhaitée. Pour chaque bloc, s'il y a un reste, ajoutez 1 au bloc. Incrémentez le pas par taille de bloc + 1 et décrémentez le reste. S'il n'y a pas de reste, donnez les morceaux normalement.

Voici la fonction et le code de test:

def trisect(s):
    return list(chunk(s, 3))

Extraits de sortie:

'abcdefghijklm'  chunk size 1 :
['abcdefghijklm']

'abcdefghijklm'  chunk size 2 :
['abcdefg', 'hijklm']

'abcdefghijklm'  chunk size 3 :
['abcde', 'fghi', 'jklm']

'abcdefghijklm'  chunk size 4 :
['abcd', 'efg', 'hij', 'klm']

'abcdefghijklm'  chunk size 5 :
['abc', 'def', 'ghi', 'jk', 'lm']

'abcdefghijklm'  chunk size 6 :
['abc', 'de', 'fg', 'hi', 'jk', 'lm']

'abcdefghijklm'  chunk size 7 :
['ab', 'cd', 'ef', 'gh', 'ij', 'kl', 'm']

'abcdefghijklm'  chunk size 8 :
['ab', 'cd', 'ef', 'gh', 'ij', 'k', 'l', 'm']

'abcdefghijklm'  chunk size 9 :
['ab', 'cd', 'ef', 'gh', 'i', 'j', 'k', 'l', 'm']

'abcdefghijklm'  chunk size 10 :
['ab', 'cd', 'ef', 'g', 'h', 'i', 'j', 'k', 'l', 'm']

'abcdefghijklm'  chunk size 11 :
['ab', 'cd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm']

'abcdefghijklm'  chunk size 12 :
['ab', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm']

'abcdefghijklm'  chunk size 13 :
['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm']
'abcdefgh'  chunk size 1 :
['abcdefgh']

'abcdefgh'  chunk size 2 :
['abcd', 'efgh']

'abcdefgh'  chunk size 3 :
['abc', 'def', 'gh']

'abcdefgh'  chunk size 4 :
['ab', 'cd', 'ef', 'gh']

'abcdefgh'  chunk size 5 :
['ab', 'cd', 'ef', 'g', 'h']

'abcdefgh'  chunk size 6 :
['ab', 'cd', 'e', 'f', 'g', 'h']

'abcdefgh'  chunk size 7 :
['ab', 'c', 'd', 'e', 'f', 'g', 'h']

'abcdefgh'  chunk size 8 :
['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h']
'abcde'  chunk size 1 :
['abcde']

'abcde'  chunk size 2 :
['abc', 'de']

'abcde'  chunk size 3 :
['ab', 'cd', 'e']

'abcde'  chunk size 4 :
['ab', 'c', 'd', 'e']

'abcde'  chunk size 5 :
['a', 'b', 'c', 'd', 'e']

Maintenant, écrire votre fonction trisect ressemble à:

def chunk(iterable, chunks):
    if chunks < 1: 
        raise ValueError("invalid chunk size")

    q, r = divmod(len(iterable), chunks)
    i = 0

    while i < len(iterable):
        if r > 0: 
            r -= 1
            yield iterable[i:i+q+1]
            i += 1
        else:
            yield iterable[i:i+q]

        i += q


if __name__ == "__main__":
    s = "".join(map(chr, range(97, 115)))

    for i in range(len(s) + 1):
        for j in range(1, len(s[:i]) + 1):
            print(repr(s[:i]), " chunk size", j, ":")
            print(list(chunk(s[:i], j)), "\n")


0 commentaires