Учитывая словарь строковых ключей и целочисленных значений, какой самый быстрый способ
</w>
к последнему элементу в кортежеДано:
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,}
Цель состоит в том, чтобы достичь:
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,}
Один из способов сделать это
я пробовал
{(tuple(k[:-1])+(k[-1]+'</w>',) ,v) for k,v in counter.items()}
В более подробной форме:
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
Есть лучший способ сделать это?
Относительно добавления кортежа и приведения его к внешнему кортежу. Почему это разрешено? Разве кортеж не должен быть неизменным?
Я бы предложил слегка модифицированную версию вашего решения. Вместо использования конструктора кортежей вы можете использовать распаковку кортежей:
>>> {(*a[:-1],f'a[-1]</w>',):b for a,b in counter.items()}
Преимущество использования распаковки кортежей в том, что вы получите лучшую производительность по сравнению с конструктором tuple
. Я расскажу об этом timeit
используя timeit
. Я буду использовать случайно сгенерированный dict
. Каждый ключ в dict
будет иметь 2 случайно выбранных символа из строчных букв, и каждое значение будет целым числом в диапазоне 0-100. Для всех этих тестов я использую Python 3.7.0
Тест с 100 элементами в 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
Тест с 1000 элементами в 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
Бенчмарк с dict опубликован под вопросом
$ 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
Вы близки к тому, чтобы внести небольшие изменения в свой код с помощью tuple
. Вы не можете изменять элементы кортежа, но вы можете заменить один кортеж другим ::
{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}
В Python 3 вы можете использовать помеченные слова в кортежах.
Ты можешь попробовать:
>>> {(*key[:-1], key[-1] + '</w>'): value for key, value in counter.items()}
Или используйте str.split
, и str.join
и '</w>'
добавив заранее:
>>> 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((' '.join(k)+'</w>').split()):v for k,v 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}
>>>
import timeit
print('bro-grammer:',timeit.timeit(lambda: [{(*a[:-1],f'a[-1]</w>',):b for a,b in counter.items()} for i in range(1000)],number=10))
print('Sandeep Kadapa:',timeit.timeit(lambda: [{tuple(key[:-1])+(key[-1]+'</w>',):value for key,value in counter.items()} for i in range(1000)],number=10))
print('U9-Forward:',timeit.timeit(lambda: [{tuple((' '.join(k)+'</w>').split()):v for k,v in counter.items()} for i in range(1000)],number=10))
Выход:
bro-grammer: 0.1293355557653911
Sandeep Kadapa: 0.20885866344797197
U9-Forward: 0.3026948357193003
Я бы пошел на что-то вроде этого:
def f(string):
l = list(string)
l[-1] = l[-1] + '</w>'
return tuple(l)
dict((f(k), v) for k, v in counter.items())
выход:
{('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}