2013-08-28 73 views
2

原諒我,如果這是顯而易見的,但我對Python非常新。我找到了從字典中獲得多個密鑰的方法,但這不是我想要做的。有沒有一種方法可以讓字典鍵成爲一個範圍?

基本上我正在尋找這樣的事情:

my_dict = { "1-10" : "foo", 
      "11-20" : "bar", 
      # ... 
      "91-100" : "baz" } 

...但密鑰是不實際的字符串,並在一定範圍映射到值的任何數字。因此,例如,my_dict[9]應該返回foo,正如my_dict[3]應該。我想用一個明確的陣列,像下面的,但沒有奏效:

my_dict = { [1, 2, 3, ..., 10] : "foo", 

我不確定這是否是即使是有效的用例的字典,或者如果有另一個數據結構我應該使用。但是Python總有一種令我驚訝的方式。那麼有沒有人知道Python的魔術來使這項工作?

+1

[this](http://stackoverflow.com/q/9043172/198633)可能會感興趣你 – inspectorG4dget

回答

1

如何:

def fancy_dict(*args): 
    'Pass in a list of tuples, which will be key/value pairs' 
    ret = {} 
    for k,v in args: 
     for i in k: 
      ret[i] = v 
    return ret 

然後,您可以:

>>> dic = fancy_dict((range(10), 'hello'), (range(100,125), 'bye')) 
>>> dic[1] 
'hello' 
>>> dic[9] 
'hello' 
>>> dic[100] 
'bye' 
>>> 

你也可以添加邏輯在fancy_dict的內部說,檢查一個項目是否是一個字符串或者它是否可迭代並相應地創建字典。

+0

不錯。這工作完美。謝謝!你還教會了我如何在Python中使用可變參數。 :) – asteri

+0

請注意'len(ret)'會給你提供不正確的值。此外,可能更重要的是,遍歷'ret'不會進入有序索引或插入順序,並且會爲給定值插入的每個範圍ID重複值。更新和添加值也不會像你想要的那樣工作。 –

2

這當然不是一個常見的情況,我建議使用明顯的解決方案:

my_dict = dict((i, "foo") for i in range(1,10)) 
print my_dict 
{1: 'foo', 2: 'foo', 3: 'foo', 4: 'foo', 5: 'foo', 6: 'foo', 7: 'foo', 8: 'foo', 9: 'foo'} 

爲了添加新的元素,你可以更新您的字典中:

my_dict.update(new_elements) 
+0

有趣。不過,你如何將其他鍵追加到現有的'my_dict'? – asteri

+0

只要你不想像'len()'這樣的東西的準確含義,並且在最初寫入它們後不需要更新這些值,這可能就沒有問題。 –

+0

當然是用my_dict.update()。 – badc0re

0

我把這個以供其他人關注:

它可以在你製作關鍵元組時使用: my_dict = {(1 ,2,3,10): 「富」}

編輯:我想你想的清單爲重點。 否則,你需要使它:

>>> import numpy as np 
>>> keys = np.arange(10,dtype=int) 
>>> values = np.arange(3,13) 
>>> d = dict(numpy.array([keys,values]).T) 
>>> d 
{0: 3, 1: 4, 2: 5, 3: 6, 4: 7, 5: 8, 6: 9, 7: 10, 8: 11, 9: 12} 
+0

這是如何工作的?如果我調用'my_dict [2]'我得到一個KeyError – Brad

+0

你必須重寫getitem/setitem上的自定義詞典來查找鍵,除非那樣,當然,你會失去字典的查找效率HashMap中。 –

+0

@Brad OK。我現在編輯。看到更新,這是你想要的。 – Developer

1

如果你的「範圍鍵」都具有獨特的映射簡單的數學變換的每一個潛在有效的密鑰,你可以只繼承list和覆蓋__getitem____setitem__,雖然有充分的理由只需在你的調用代碼中使用助手方法或直接計算(例如讓index()返回特別有意義的內容)。

class RangeList(list): 
    def __getitem__(self, index): 
     return super(RangeList, self).__getitem__(index/10 if index else 0) 
    def __setitem__(self, index, value): 
     super(RangeList, self).__setitem__(index/10 if index else 0, value) 
3

我必須說我從來沒有任何需要做這樣的事情,當然也沒有內置的數據結構。 (如果你知道關於散列的任何事情,你就會明白爲什麼字典不能這樣工作。)

一種可能性是根本不使用字典,但有單獨的鍵和值列表,關鍵列表是每個「範圍」的開始。所以:

keys = [0, 10, 20, 30] 
values = ['foo', 'bar', 'baz', 'quux'] 

現在你可以使用bisect找到相關的關鍵:

import bisect 
pos = bisect.bisect_left(keys, 12) 
value = values[pos-1] 
+0

+1爲完全不同的方法。像('1-10','12-20')這樣的差距呢? – Stefan

0

瑪貝你可以沿着thise線做一些事情:

class my_dict(dict): 
    def __getitem__(self, a): 
     return dict.__getitem__(self, (a-1)/10) 
    def __setitem__(self, a, b): 
     dict.__setitem__(self, (a-1)/10, b) 

dict_instance = my_dict() 
dict_instance[1] = 'foo' 
print dict_instance[9] # prints foo 

dict_instance[17] = 'bar' 
print dict_instance[12] # prints bar 

這有快beeing作爲普通字典的atvantage(O(1)),但小10倍

你還需要ovewrite __ str__如果你想要它打印範圍,你也可以通過這個數據類型很容易地遍歷唯一的鍵:)

相關問題