7
votes

Quel est le moyen le plus rapide de diviser les clés de dictionnaire en tuples de type chaîne et d'ajouter une autre chaîne aux derniers éléments des tuples?

Étant donné un dictionnaire de valeurs de clé de chaîne et d'entiers, quel est le moyen le plus rapide de

  1. diviser chaque clé en un tuple de clé de type chaîne
  2. puis ajoutez une sous-chaîne spéciale au dernier élément du tuple

Given:

new_counter = {}
for k, v in counter.items():
    left = tuple(k[:-1])
    right = tuple(k[-1]+'w',)
    new_k = (left + right,)
    new_counter[new_k] = v

L'objectif est d'atteindre:

{(tuple(k[:-1])+(k[-1]+'</w>',) ,v) for k,v in counter.items()}

Une façon de le faire est à

  • parcourir le compteur et
  • conversion de tous les caractères sauf le dernier en tuple
  • ajouter au tuple et créer un tuple externe
  • et attribuez la clé de tuple au nombre

J'ai essayé

counter = {('T', 'h', 'e</w>'): 6149,
 ('P', 'r', 'o', 'j', 'e', 'c', 't</w>'): 205,
 ('G', 'u', 't', 'e', 'n', 'b', 'e', 'r', 'g</w>'): 78,
 ('E', 'B', 'o', 'o', 'k</w>'): 5,
 ('o', 'f</w>'): 39169,
 ('A', 'd', 'v', 'e', 'n', 't', 'u', 'r', 'e', 's</w>'): 2,
 ('S', 'h', 'e', 'r', 'l', 'o', 'c', 'k</w>'): 95,
 ('H', 'o', 'l', 'm', 'e', 's</w>'): 198,
 ('b', 'y</w>'): 6384,
 ('S', 'i', 'r</w>'): 30,
 ('A', 'r', 't', 'h', 'u', 'r</w>'): 18,
 ('C', 'o', 'n', 'a', 'n</w>'): 3,
 ('D', 'o', 'y', 'l', 'e</w>'): 2,}

De manière plus détaillée:

counter = {'The': 6149,
     'Project': 205,
     'Gutenberg': 78,
     'EBook': 5,
     'of': 39169,
     'Adventures': 2,
     'Sherlock': 95,
     'Holmes': 198,
     'by': 6384,
     'Sir': 30,
     'Arthur': 18,
     'Conan': 3,
     'Doyle': 2,}

Est y a-t-il une meilleure façon de faire cela?

Concernant l'ajout d'un tuple et le transtypage vers un tuple externe. Pourquoi est-ce autorisé? Le tuple n'est-il pas censé être immuable?


2 commentaires

Il semble que votre question appartienne à CodeReview.


Cela est possible car vous créez un NOUVEAU dictionnaire et ses clés sont des tuples DIFFÉRENTS. Les clés d'origine du dictionnaire sont en effet immuables et vous ne les modifiez pas.


6 Réponses :


3
votes

Vous êtes sur le point d'apporter quelques modifications à votre code en utilisant tuple . Vous ne pouvez pas modifier les éléments d'un tuple, mais vous pouvez remplacer un tuple par un autre ::

{tuple(key[:-1])+(key[-1]+'</w>',):value for key,value in counter.items()}

{('T', 'h', 'e</w>'): 6149,
 ('P', 'r', 'o', 'j', 'e', 'c', 't</w>'): 205,
 ('G', 'u', 't', 'e', 'n', 'b', 'e', 'r', 'g</w>'): 78,
 ('E', 'B', 'o', 'o', 'k</w>'): 5,
 ('o', 'f</w>'): 39169,
 ('A', 'd', 'v', 'e', 'n', 't', 'u', 'r', 'e', 's</w>'): 2,
 ('S', 'h', 'e', 'r', 'l', 'o', 'c', 'k</w>'): 95,
 ('H', 'o', 'l', 'm', 'e', 's</w>'): 198,
 ('b', 'y</w>'): 6384,
 ('S', 'i', 'r</w>'): 30,
 ('A', 'r', 't', 'h', 'u', 'r</w>'): 18,
 ('C', 'o', 'n', 'a', 'n</w>'): 3,
 ('D', 'o', 'y', 'l', 'e</w>'): 2}


0 commentaires

0
votes

Je choisirais quelque chose comme ceci:

{('A', 'd', 'v', 'e', 'n', 't', 'u', 'r', 'e', 's</w>'): 2,
 ('A', 'r', 't', 'h', 'u', 'r</w>'): 18,
 ('C', 'o', 'n', 'a', 'n</w>'): 3,
 ('D', 'o', 'y', 'l', 'e</w>'): 2,
 ('E', 'B', 'o', 'o', 'k</w>'): 5,
 ('G', 'u', 't', 'e', 'n', 'b', 'e', 'r', 'g</w>'): 78,
 ('H', 'o', 'l', 'm', 'e', 's</w>'): 198,
 ('P', 'r', 'o', 'j', 'e', 'c', 't</w>'): 205,
 ('S', 'h', 'e', 'r', 'l', 'o', 'c', 'k</w>'): 95,
 ('S', 'i', 'r</w>'): 30,
 ('T', 'h', 'e</w>'): 6149,
 ('b', 'y</w>'): 6384,
 ('o', 'f</w>'): 39169}

sortie:

def f(string):
    l = list(string)
    l[-1] = l[-1] + '</w>'
    return tuple(l)
dict((f(k), v) for k, v in counter.items())


0 commentaires

5
votes

Je proposerais une version légèrement modifiée de votre solution. À la place d'utiliser constructeur de tuple, vous pouvez utiliser le décompression de tuple:

$ python -m timeit -s "import random" -s "import string" -s "counter = counter = {'The': 6149, 'Project': 205, 'Gutenberg': 78, 'EBook': 5, 'of': 39169, 'Adventures': 2, 'Sherlock': 95, 'Holmes': 198, 'by': 6384, 'Sir': 30, 'Arthur': 18, 'Conan': 3,'Doyle': 2}" "{(*a[:-1],f'a[-1]</w>',):b for a,b in counter.items()}"
$ 50000 loops, best of 5: 7.28 usec per loop

$ python -m timeit -s "import random" -s "import string" -s "counter = counter = {'The': 6149, 'Project': 205, 'Gutenberg': 78, 'EBook': 5, 'of': 39169, 'Adventures': 2, 'Sherlock': 95, 'Holmes': 198, 'by': 6384, 'Sir': 30, 'Arthur': 18, 'Conan': 3,'Doyle': 2}" "{tuple(key[:-1])+(key[-1]+'</w>',):value for key,value in counter.items()}"
$ 20000 loops, best of 5: 11 usec per loop

L'avantage d'utiliser le décompression de tuple est que vous obtiendrez de meilleures performances par rapport au constructeur de tuple . Je vais vous éclairer davantage à ce sujet en utilisant timeit . J'utiliserai dict généré aléatoirement. Chaque clé du dict aura 2 caractères choisis au hasard parmi les lettres minuscules et chaque valeur sera un entier compris entre 0 et 100. Pour tous ces benchmarks, j'utilise Python 3.7.0

Benchmark avec 100 éléments dans dict

$ python -m timeit -s "import random" -s "import string" -s "counter = {''.join(random.sample(string.ascii_lowercase,2)): random.randint(0,100) for _ in range(1000)}" "{(*a[:-1],f'a[-1]</w>',):b for a,b in counter.items()}"
$ 1000 loops, best of 5: 192 usec per loop

$ python -m timeit -s "import random" -s "import string" -s "counter = {''.join(random.sample(string.ascii_lowercase,2)): random.randint(0,100) for _ in range(1000)}" "{tuple(key[:-1])+(key[-1]+'</w>',):value for key,value in counter.items()}"
$ 1000 loops, best of 5: 321 usec per loop

Benchmark avec 1000 éléments dans dict

$ python -m timeit -s "import random" -s "import string" -s "counter = {''.join(random.sample(string.ascii_lowercase,2)): random.randint(0,100) for _ in range(100)}" "{(*a[:-1],f'a[-1]</w>',):b for a,b in counter.items()}
$ 10000 loops, best of 5: 36.6 usec per loop

$ python -m timeit -s "import random" -s "import string" -s "counter = {''.join(random.sample(string.ascii_lowercase,2)): random.randint(0,100) for _ in range(100)}" "{tuple(key[:-1])+(key[-1]+'</w>',):value for key,value in counter.items()}"
$ 5000 loops, best of 5: 59.7 usec per loop

Benchmark avec dict posté en question

>>> {(*a[:-1],f'a[-1]</w>',):b for a,b in counter.items()}


0 commentaires

2
votes

Ou utilisez str.split , et faites str.join et '' en ajoutant au préalable:

bro-grammer: 0.1293355557653911
Sandeep Kadapa: 0.20885866344797197
U9-Forward: 0.3026948357193003


0 commentaires

0
votes

Avec Python 3, vous pouvez utiliser une expression étoilée dans les tuples.

Vous pouvez essayer:

>>> {(*key[:-1], key[-1] + '</w>'): value for key, value in counter.items()}


0 commentaires

0
votes

Vous pouvez également supprimer .items () de votre itération et procéder comme suit:

 timeit.timeit(lambda: {tuple(i[:-1]) + (i[-1]+'w',):counter[i] for i in counter}, number=10)
 0.000192291005179286

C'est un peu plus rapide.

{tuple(i[:-1]) + (i[-1]+'</w>',):counter[i] for i in counter}


0 commentaires