2014-09-05 49 views
0

我想創建一個查找表,並且我正在考慮使用字典。該字典將具有對應於整數的鍵(或者對於類Enum中的枚舉類型),並且值將是2,3或4個numpy數組。但不知何故,我不願意使用這種方法,因爲這本字典有大量的信息,其中有99%的信息可能不會用於某些問題。因此,構建包含所有查找信息的單個對象是沒有意義的,即使我在猜測,我幾乎可以肯定有更好的方法來完成我想要做的事情。所以來自C++世界,我會創建一個枚舉類型unordered_map函數指針,其中函數我會創建一個static數組(以便它將被創建一次),然後我會返回數組中指針。通過這種方式,我只會實例化程序真正需要的部分查找表,而不是整個事情。創建一個巨大的查找表,關於性能問題

但我想在Python中做類似的事情,所以我想知道什麼是最有效的方法來實現這一點。

編輯

原來這就是我想出了這麼遠。我喜歡@AaronDigulla和@DanielRoseman提出的建議,儘管@runonce可能不再必要。 dict的子類覆蓋__getitem__方法並檢查字典中是否存在密鑰。如果沒有,它會調用一個函數(在字典鍵值中使用連接字符串上的eval())。我將不勝感激對給定代碼的任何改進。它看起來相當複雜,但它的工作原理,所以我想知道它是否可以進一步簡化。

import collections, types 
import numpy as np 

Quadrature = collections.namedtuple("Quadrature", "wgt xi eta zeta") 

category_map = { "t3" : "tri" #... more types 
       } 


class Integrator(dict): 

    def __init__(self, *args, **kwargs): 
    self.update(*args, **kwargs) 

    def __getitem__(self, key): 

    if not key in self: 

     fn = '{}_{}gp'.format(category_map[key[0]], str(key[1])) 
     super().__setitem__(key, eval(fn)()) 

    val = super().__getitem__(key) 
    return val 

    def __repr__(self): 
    dictrepr = dict.__repr__(self) 
    return '%s(%s)' % (type(self).__name__, dictrepr) 

    def update(self, *args, **kwargs): 
    print ('update', args, kwargs) 
    for k, v in dict(*args, **kwargs).items(): 
     self[k] = v 

def run_once(f): 
    def wrapper(*args, **kwargs): 
    if not wrapper.has_run: 
     wrapper.has_run = True 
     return f(*args, **kwargs) 
    wrapper.has_run = False 
    return wrapper 


@run_once 
def tri_3gp(): 
    xi = np.array([2/3., 1/6., 1/6.]) 
    eta = np.array([1/6., 1/6., 2/3.]) 
    wgt = np.array([2/3., 2/3., 2/3.]); 
    return Quadrature(wgt, xi, eta, None) 
+0

嘗試p字典,他們工作hashmaps - 並有一些良好的表現。他們的數據集實際上是否太慢? (你測試過了嗎?)。如果你只需要一些結果,那麼你甚至可以覆蓋它來「緩存」一些結果 - 從而提高查找速度。 – Etse 2014-09-05 07:42:20

+0

巨大的意思是它仍然適合記憶?你的價值觀來自哪裏?你已經知道memcache/momorise作爲裝飾者了嗎?也許看看這裏例如:http://blog.isotoma.com/2009/09/of-python-memcached-and-decorators-easy-peasy-function-caching/ – Argeman 2014-09-05 07:43:04

+0

[這個問題](http:// stackoverflow.com/questions/1988804/what-is-memoization-and-how-can-i-use-it-in-python)可能對你有用,以及[作爲函數裝飾器的這個實現](https ://wiki.python.org/moin/PythonDecoratorLibrary#Memoize)。 – Carsten 2014-09-05 07:44:40

回答

1

你可以在Python中完成同樣的事情。事實上,它更容易,因爲函數本身就是一流的對象:您可以將它們存儲在字典中並根據需要調用它們。

要替換靜態數組,您可以使用某種記憶方式,例如標準的全局查找數組。

global_dict = {} 

def func1(): 
    if 'param1' not in global_dict: 
     global_dict['param1'] = my_complicated_function_for_param_1() 
    return global_dict['param1'] = my_complicated_function_for_param_1() 



lookup_dict = { 
    'param1': func1, 
    ... 
} 

# now do the lookup: 
my_result = lookup_dict[my_param]() 

當然,你可能想分解出從計算功能的邏輯:一個裝飾可能是一個不錯的辦法。

1

這在Python中很簡單。看到這個問題如何創建「運行一次」裝飾器:Efficient way of having a function only execute once in a loop

現在你可以把這些函數在地圖上創建數據。裝飾者將確保他們最多運行一次(第一次給他們打電話)。然後loopup會是這樣:

@run_once 
def funcForKey(): 
    ... 

lookup_dict = { 
    'key': funcForKey, 
    ... 
} 

result = lookup_dict[x]() 

()[]後調用函數。

你也可以試試類:

class Data(object): 
    @run_once 
    def key(self): 
     ... 

data = Data() 

現在你可以看一下值,就像這樣:

a = 'key' 
result = getattr(data, a)() 

或者,如果名稱在運行時是恆定的,簡單地說:

result = data.key() 
+0

所以你暗示的是我可以使用這種類型的裝飾器來按需填充地圖? – aaragon 2014-09-05 08:12:26

+0

是的。裝飾器爲你做緩存。 – 2014-09-05 09:07:18