沒有內置到Python的一個數據結構,你想要做的一切,但使用它可以實現您的目標並相當有效地完成的組合相當容易。
例如,假設你的輸入是在一個逗號分隔值文件中的以下數據稱爲employees.csv
具有被定義爲示出由第一行的字段名稱:
name,age,weight,height
Bob Barker,25,175,6ft 2in
Ted Kingston,28,163,5ft 10in
Mary Manson,27,140,5ft 6in
Sue Sommers,27,132,5ft 8in
Alice Toklas,24,124,5ft 6in
下面是工作的代碼示出了如何讀取這些數據並將其存儲到記錄列表中,並自動創建單獨的查找表,以查找與這些記錄中每個字段中包含的值相關的記錄。
記錄是由namedtuple
創建的類的實例,它具有很高的內存效率,因爲每個類缺少類實例通常包含的__dict__
屬性。使用它們可以使用點語法按名稱訪問每個字段,如record.fieldname
。
該查找表是defaultdict(list)
實例,這提供關於平均類字典ø(1)查找時間,並且還允許多個值與每一個相關聯。因此,查找鍵是要查找的字段值的值,並且與其關聯的數據將是Person
列表中存儲的Person
記錄的整數索引列表,並且具有該值 - 因此它們都是相對的小。
請注意,該類的代碼完全是數據驅動的,因爲它不包含任何硬編碼的字段名,它們在讀入時取自csv數據輸入文件的第一行。使用時,任何實際的retrieve()
方法調用當然必須包含有效的字段名稱關鍵字參數。
更新
修改爲各個領域的每一個獨特的價值,當數據文件先讀不創建一個查找表。現在retrieve()
方法只根據需要創建它們(並保存/緩存結果以供將來使用)。還修改爲使用Python 2.7+,包括3.x.
from collections import defaultdict, namedtuple
import csv
class DataBase(object):
def __init__(self, csv_filename, recordname):
# Read data from csv format file into a list of namedtuples.
with open(csv_filename, 'r') as inputfile:
csv_reader = csv.reader(inputfile, delimiter=',')
self.fields = next(csv_reader) # Read header row.
self.Record = namedtuple(recordname, self.fields)
self.records = [self.Record(*row) for row in csv_reader]
self.valid_fieldnames = set(self.fields)
# Create an empty table of lookup tables for each field name that maps
# each unique field value to a list of record-list indices of the ones
# that contain it.
self.lookup_tables = defaultdict(lambda: defaultdict(list))
def retrieve(self, **kwargs):
""" Fetch a list of records with a field name with the value supplied
as a keyword arg (or return None if there aren't any). """
if len(kwargs) != 1: raise ValueError(
'Exactly one fieldname/keyword argument required for function '
'(%s specified)' % ', '.join([repr(k) for k in kwargs.keys()]))
field, value = list(kwargs.items())[0] # Get only keyword arg and value.
if field not in self.valid_fieldnames:
raise ValueError('keyword arg "%s" isn\'t a valid field name' % field)
if field not in self.lookup_tables: # Must create field look up table.
for index, record in enumerate(self.records):
value = getattr(record, field)
self.lookup_tables[field][value].append(index)
matches = [self.records[index]
for index in self.lookup_tables[field].get(value, [])]
return matches if matches else None
if __name__ == '__main__':
empdb = DataBase('employees.csv', 'Person')
print("retrieve(name='Ted Kingston'): {}".format(empdb.retrieve(name='Ted Kingston')))
print("retrieve(age='27'): {}".format(empdb.retrieve(age='27')))
print("retrieve(weight='150'):".format(empdb.retrieve(weight='150')))
try:
print("retrieve(hight='5ft 6in'):".format(empdb.retrieve(hight='5ft 6in')))
except ValueError as e:
print("ValueError('{}') raised as expected".format(e))
else:
raise type('NoExceptionError', (Exception,), {})(
'No exception raised from "retrieve(hight=\'5ft\')" call.')
輸出:
retrieve(name='Ted Kingston'): [Person(name='Ted Kingston', age='28', weight='163', height='5ft 10in')]
retrieve(age='27'): [Person(name='Mary Manson', age='27', weight='140', height='5ft 6in'),
Person(name='Sue Sommers', age='27', weight='132', height='5ft 8in')]
retrieve(weight='150'): None
retrieve(hight='5ft 6in'): ValueError('keyword arg "hight" is an invalid fieldname')
raised as expected
能否請您證明-1?這是一個真正的編程問題。 – 2013-03-14 19:27:17
也許這會幫助你 - http://wiki.python.org/moin/TimeComplexity? – kgr 2013-03-14 19:35:48
爲什麼不使用sql呢?似乎更適合。 Python已經內置了對sqlite的支持。 – 2013-03-14 19:40:38