我有一個帶有鍵:值串列配對的字典,我打算找到包含所需元素的值串列的索引。
例如,如果字典是:
my_dict = {"key1":['v1'], "key2":None, "key3":['v2','v3'], "key4":['v4','v5','v6']}
然后,給定元素,'v2'我應該能夠獲得索引 2。
對于具有一個元素的值串列,可以通過以下方式獲得索引:list(my_dict.values()).index(['v1']),但是這種方法不適用于包含多個元素的串列。
使用for回圈,可以通過以下方式獲得:
for key, value in my_dict.items():
if value is None:
continue
if 'v2' in value:
print (list(my_dict.keys()).index(key))
有沒有更簡潔的(pythonic)方法來獲得相同的?
uj5u.com熱心網友回復:
你有一個 XY 問題。您想知道指向某個值的鍵,并且您認為需要找到迭代值的列舉索引,這樣您就可以使用它通過迭代來查找鍵。你不需要這一切。直接找鑰匙就好了:
my_dict = {"key1":['v1'], "key2":None, "key3":['v2','v3'], "key4":['v4','v5','v6']}
value = 'v2'
# Iterate key/vals pairs in genexpr; if the vals contains value, yield the key,
# next stops immediately for the first key yielded so you don't iterate the whole dict
# when the value is found on an early key
key_for_value = next(key for key, vals in my_dict.items() if vals and value in vals)
print(key_for_value)
在線嘗試!
StopIteration如果該值不存在,則會引發該問題,否則它將直接檢索該鍵的值list包含所需值的第一個鍵。
如果您真的沒有 XY 問題,并且索引很重要(它不應該是,這是對dicts 的濫用),那么生成它也很簡單,更改密鑰的提取以獲得兩者,例如:
index, key_for_value = next((i, key) for i, (key, vals) in enumerate(my_dict.items()) if vals and value in vals)
請注意,如果您需要大量執行這些查找并且my_dict不是非常小,這是一個糟糕的解決方案;它O(n)是值的總數,因此dict需要很長時間才能檢查(相對于僅查找任意鍵的成本,即 average-case O(1))。在這種情況下,理想情況下,如果my_dict變化不大/根本沒有變化,您會預先構建一個反向字典來查找與值關聯的鍵,例如:
from collections import defaultdict
my_dict = {"key1":['v1'], "key2":None, "key3":['v2','v3'], "key4":['v4','v5','v6']}
reversed_my_dict = defaultdict(set)
for key, vals in my_dict:
for val in vals:
reversed_my_dict[val].add(key)
reversed_my_dict = dict(reversed_my_dict) # Optional: Prevents future autovivification of keys
# by converting back to plain dict
之后,您可以通過以下方式廉價地確定與給定值關聯的鍵:
reversed_my_dict.get(value, ()) # Using .get prevents autovivification of keys even if still a defaultdict
which returns the set of all keys that map to that value, if any, or the empty tuple if not (if you convert back to dict above, reversed_my_dict[value] would also work if you'd prefer to get a KeyError when the value is missing entirely; leaving it a defaultdict(set) would silently construct a new empty set, map it to the key and return it, which is fine if this happens rarely, but a problem if you test thousands of unmapped values and create a corresponding thousands of empty sets for no benefit, consuming memory wastefully).
Which you choose depends on how big my_dict is (for small my_dict, O(n) work doesn't really matter that much), how many times you need to search it (fewer searches mean less gain from reversed dict), and whether it's regularly modified. For that last point, if it's never modified, or rarely modified between lookups, rebuilding the reversed dict from scratch after each modification might be worth it for simplicity (assuming you perform many lookups per rebuild); if it's frequently modified, the reversed dict might still be worth it, you'd just have to update both the forward and reversed dicts rather than just one, e.g., expanding:
# New key
my_dict[newkey] = [newval1, newval2]
# Add value
my_dict[existingkey].append(newval)
# Delete value
my_dict[existingkey].remove(badval)
# Delete key
del my_dict[existingkey]
to:
# New key
newvals = my_dict[newkey] = [newval1, newval2]
for newval in newvals:
reversed_my_dict[newval].add(newkey) # reversed_my_dict.setdefault(newval, set()).add(newkey) if not defaultdict(set) anymore
# Add value
my_dict[existingkey].append(newval)
reversed_my_dict[newval].add(existingkey) # reversed_my_dict.setdefault(newval, set()).add(existingkey) if not defaultdict(set) anymore
# Delete value
my_dict[existingkey].remove(badval)
if badval not in my_dict[existingkey]: # Removed last copy; test only needed if one key can hold same value more than once
reversed_my_dict[badval].discard(existingkey)
# Optional delete badval from reverse mapping if last key removed:
if not reversed_my_dict[badval]:
del reversed_my_dict[badval]
# Delete key
# set() conversion not needed if my_dict's value lists guaranteed not to contain duplicates
for badval in set(my_dict.pop(existingkey)):
reversed_my_dict[badval].discard(existingkey)
# Optional delete badval from reverse mapping if last key removed:
if not reversed_my_dict[badval]:
del reversed_my_dict[badval]
分別使修改所產生的作業量大致翻倍,以換取始終O(1)在任一方向進行查找。
uj5u.com熱心網友回復:
如果您正在尋找與某個值對應的鍵,您可以像這樣反轉字典:
reverse_dict = {e: k for k, v in my_dict.items() if v for e in v}
不過要小心重復值。最后一次出現將覆寫以前的出現。
uj5u.com熱心網友回復:
不知道這是否是最好的解決方案,但這有效:
value = 'v2'
list(map(lambda x : value in x, list(map(lambda x : x[1] or [], list(my_dict.items()))))).index(True)
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/427612.html
標籤:Python python-3.x 列表 字典
