[英]How do I efficiently extract all elements in a column from a dictionary whose values are 2D lists in Python?
[英]How to extact elements from dictionary of lists efficiently?
這是我最初的字典:
dic = {'key1': [2,3],
'key2': [5,1],
'key3': [6,8]}
注意:出於示例的目的(我這邊的 dfs 列表),我使用簡單的數字 2,3 等。
對於每個鍵,我想提取第一個元素並獲得以下結果:
dic2 = {'key1': 2,
'key2': 5,
'key3': 6}
是否可以在不進行緩慢的 for 循環的情況下做到這一點? 字典很大。。。
非常感謝您的幫助。
如果您希望在此轉換后僅訪問字典的幾個鍵,您可以編寫一個包裝器; 就像是:
class ViewFirst:
def __init__(self, original):
self.original = original
def __getitem__(self, key):
return self.original[key][0]
另一種選擇是基於defaultdict
; 這會讓你做一些事情,比如將新值分配給字典(新的或現有的鍵),同時仍然從原始字典中檢索其他值:
class DictFromFirsts(collections.defaultdict):
def __init__(self, original):
self.original = original
def __missing__(self, key):
return self.original[key][0]
編輯:根據評論中的討論,這是針對特定場景的一種特殊用途的方法。 對於通用用途,更喜歡其他答案中的一種方法,例如U12-Forward 的字典理解{k: v[0] for k, v in dic.items()}
; 它清晰明了,這通常是更重要的問題。
字典理解是通往 go 的方式:
{k: v[0] for k, v in dic.items()}
或者使用operator.itemgetter
:
>>> from operator import itemgetter
>>> dict(zip(dic, map(itemgetter(0), dic.values())))
{'key1': 2, 'key2': 5, 'key3': 6}
>>>
就我個人而言,我會 go 使用一個在引擎蓋下使用 Cython 的庫: cytoolz
pip3 install cytoolz
from cytoolz import valmap , first
dic = {'key1': [2,3],
'key2': [5,1],
'key3': [6,8]}
dic2 = valmap(first, dic)
我將使用我的 function 基准擴展 @don'ttalkjustcode 測試,我仍在嘗試找出如何測試 @Jiří Baum 的測試。
使用@don'ttalkjustcode 通用代碼for k, (dic2[k], *_)
三元素字典:
457 ns 457 ns 467 ns U12_Forward_1
775 ns 775 ns 776 ns U12_Forward_2
1021 ns 1021 ns 1036 ns user1740577
430 ns 430 ns 432 ns Marco_DG
679 ns 679 ns 683 ns dont_talk_just_code
12k 元素字典:
992967 ns 997872 ns 998554 ns U12_Forward_1
1251728 ns 1254163 ns 1254897 ns U12_Forward_2
1434998 ns 1436245 ns 1440789 ns user1740577
1219357 ns 1219453 ns 1225301 ns Marco_DG
2208451 ns 2213086 ns 2214531 ns dont_talk_just_code
三元素字典:
422 ns 422 ns 422 ns marco_dg
462 ns 462 ns 462 ns U12_Forward_1
765 ns 766 ns 769 ns U12_Forward_2
1076 ns 1081 ns 1088 ns user1740577
341 ns 341 ns 341 ns dont_talk_just_code
12k 元素字典:
1206537 ns 1208705 ns 1211105 ns marco_dg
1009374 ns 1011324 ns 1011989 ns U12_Forward_1
1232356 ns 1232728 ns 1251990 ns U12_Forward_2
1380953 ns 1382381 ns 1390140 ns user1740577
848863 ns 850010 ns 850450 ns dont_talk_just_code
讓我們看看這里的 for 循環到底有多“慢”。 我的解決方案:
dic2 = {}
for k, (dic2[k], _) in dic.items():
pass
用你的玩具字典進行基准測試:
600 ns 602 ns 603 ns U12_Forward_1
1019 ns 1025 ns 1027 ns U12_Forward_2
1347 ns 1350 ns 1355 ns user1740577
441 ns 442 ns 443 ns dont_talk_just_code
正如您評論的那樣,使用包含 12k 個項目的“大”字典進行基准測試:
1412624 ns 1414927 ns 1418089 ns U12_Forward_1
1687464 ns 1690134 ns 1696759 ns U12_Forward_2
1961205 ns 1986729 ns 2005884 ns user1740577
1248901 ns 1260306 ns 1261295 ns dont_talk_just_code
以上是在 tio.run 上完成的,我使用它是因為它的高速和速度穩定性。 可悲的是,它沒有提供 Marco 的答案所需的cytoolz
,所以我不能包括它。 然后@user1740577 指責我撒謊,因為我沒有包括它,所以這里是 replit.com 的結果,我可以在哪里(請注意,如果你在那里運行它並且沒有付費帳戶,你的時間會更慢) :
475 ns 476 ns 484 ns U12_Forward_1
804 ns 805 ns 807 ns U12_Forward_2
1075 ns 1079 ns 1082 ns user1740577
442 ns 444 ns 448 ns Marco_DG
360 ns 360 ns 360 ns dont_talk_just_code
1060461 ns 1061449 ns 1071588 ns U12_Forward_1
1294079 ns 1330157 ns 1706065 ns U12_Forward_2
1593082 ns 1594114 ns 1596703 ns user1740577
1268663 ns 1274264 ns 1286715 ns Marco_DG
964445 ns 965971 ns 966333 ns dont_talk_just_code
完整的基准代碼(也在replit :
from timeit import repeat
from functools import partial
from operator import itemgetter
from cytoolz import valmap , first
def U12_Forward_1(dic):
return {k: v[0] for k, v in dic.items()}
def U12_Forward_2(dic):
return dict(zip(dic, map(itemgetter(0), dic.values())))
def user1740577(dic):
return dict(zip(dic.keys(),list(list(zip(*dic.values()))[0])))
def Marco_DG(dic):
return valmap(first, dic)
def dont_talk_just_code(dic):
dic2 = {}
for k, (dic2[k], _) in dic.items():
pass
return dic2
funcs = U12_Forward_1, U12_Forward_2, user1740577, Marco_DG, dont_talk_just_code
def bench(dic, number):
expect = funcs[0](dic)
for func in funcs:
result = func(dic)
print(result == expect, func.__name__)
print()
for _ in range(3):
for func in funcs:
ts = sorted(repeat(partial(func, dic), number=number))[:3]
print(*('%7d ns ' % (t / number * 1e9) for t in ts), func.__name__)
print()
bench({'key1': [2,3], 'key2': [5,1], 'key3': [6,8]}, 100000)
bench({f'key{i}': [i,42] for i in range(12000)}, 30)
你可以試試這個:
dict(zip(dic.keys(),list(list(zip(*dic.values()))[0])))
Output:
{'key1': 2, 'key2': 5, 'key3': 6}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.