没有内置到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