1
votes

Comment effectuer la suppression sur place des doublons d'une chaîne en Python?

J'essaie d'implémenter un algorithme en place pour supprimer les doublons d'une chaîne en Python.

str1 = "geeksforgeeks"
for i in range(len(str1)):
    for j in range(i+1,len(str1)-1):
         if str1[i] == str1[j]:  //Error Line
                      str1 = str1[0:j]+""+str1[j+1:]



print str1

Dans le code ci-dessus, j'essaie de remplacer le caractère dupliqué par des espaces. Mais j'obtiens IndexError: string index out of range à if str1 [i] == str1 [j] . Suis-je en train de rater quelque chose ou n'est-ce pas la bonne façon?

Mon résultat attendu est: geksfor


15 commentaires

i prend la valeur de tous les indices valides de str1 . Alors j est i + 1 . Lorsque i est l'indice valide le plus élevé, j est donc hors de portée.


Quelle est la valeur attendue?


@Alderven Quand i vaut 0 et j vaut 10, j'obtiens IndexError


@Alderven La sortie attendue est: geksfor


@ TigerhawkT3 quand i est 10, j est 10 et la longueur de la chaîne est 10, j


Vous modifiez la longueur de la chaîne en la parcourant, donc la plage change.


Vous ne pouvez pas effectuer de modification sur place d'une chaîne en Python. Les chaînes sont immuables.


@Jab J'essaye de faire en place, donc je ne peux pas utiliser un autre tableau.


@AdamSmith Mais c'était une question de concours.


@ Animeartistfromhell7 alors le concours est absurde. Vous ne pouvez pas modifier les chaînes sur place en Python. Arrêt complet.


@AdamSmith Alors je devrais essayer une autre langue? comme C?


@ Animeartistfromhell7 Je n'ai aucune expérience en C, donc je ne pourrais pas vous le dire, mais vous ne pouvez pas faire cela en Python. Cela brise la spécification du langage (les chaînes sont immuables)


@ Animeartistfromhell7 Vous pouvez utiliser un bytearray , qui est mutable.


"quand i est 10, j est 10" Pourquoi serait-ce le cas lorsque la boucle interne pour laquelle j est la variable de boucle utilise un objet range commençant par i + 1 ?


@Keith uniquement s'il utilise uniquement des chaînes ascii. Les chaînes Python sont unicode depuis Python3.


4 Réponses :


0
votes

Il est impossible de modifier les chaînes en place en Python, de la même manière qu'il est impossible de modifier les nombres en place en Python.

a = "something"
b = 3

b += 1        # allocates a new integer, 4, and assigns it to b
a += " else"  # allocates a new string, " else", concatenates it to `a` to produce "something else"
              # then assigns it to a


0 commentaires

1
votes

Vous pouvez faire tout cela avec juste un ensemble et une compréhension. Pas besoin de compliquer les choses.

from collections import OrderedDict
print("".join(OrderedDict.fromkeys(str1)))

"Le simple vaut mieux que le complexe."

~ Voir PEP20 p>

Bien que ce qui précède soit plus simple que votre réponse, c'est le moyen le plus performant de supprimer les doublons d'une collection la solution la plus simple serait d'utiliser:

str1 = "geeksforgeeks"

seen = set()
seen_add = seen.add
print(''.join(s for s in str1 if not (s in seen or seen_add(s))))
#geksfor


5 commentaires

C'est une utilisation intéressante (non évidente) du conditionnel ou . Ce qui veut dire "Merci! Je déteste ça!"


Je suis désolé? Je ne suis pas sûr de suivre.


Il existe des solutions simples: stackoverflow.com/questions / 9841303 /…


Eh bien, tout en gardant la simplicité et la performance, je dis cette réponse est ce que je préfère. Et je dis la simplicité par rapport à la solution d'OP.


@AdamSmith - Elle a été retirée d'une une autre réponse , dont la citation a finalement été ajoutée dans le quatrième révision .



0
votes

Comme déjà indiqué, str est immuable, donc l'exigence in-place n'a aucun sens. Si vous voulez obtenir la sortie souhaitée, je le ferais de la manière suivante:

str1 = 'geeksforgeeks'
out = ''.join([i for inx,i in enumerate(str1) if str1.index(i)==inx])
print(out) #prints: geksfor

Ici, j'ai utilisé la fonction enumerate pour obtenir une numérotation ( inx ) lettres et le fait que la méthode .index de str , renvoie l'index le plus bas possible de l'élément donc str1.index ('e') pour la chaîne donnée est 1 , pas 2 , pas 9 et pas 10.


0 commentaires

0
votes

Voici une version simplifiée de unique_everseen de recettes itertools .

str1 = "geeksforgeeks"
new_str1 = ''.join(unique_everseen(str1)) # 'geksfor'

Vous pouvez ensuite utiliser ce générateur avec str.join pour obtenir le résultat attendu.

from itertools import filterfalse

def unique_everseen(iterable)
    seen = set()
    see _ add = seen.add
    for element in filterfalse(seen.__contains__, iterable):
        seen_add(element)
        yield element


0 commentaires