目前有一个字典形式的数据结构,其中每个值都是一个包含数字值的数据列表。这些数字列表中的每一个都包含了可以使用 SQL 术语来称之为主键的什么东西,包含了前三个值:年份、球员标识符和球队标识符。这是字典中的键。因此,可以通过为年份、球员 ID和球队 ID传递值来获取唯一行,如下所示:
statline = stats[(2001, 'SEA', 'suzukic01')]
这会产生类似这样的结果:
[305, 20, 444, 330, 45]
希望这个数据结构可以快速地按这三个键中的任何一个进行求和:因此,可以轻松地通过传递年份、球员 ID和球队 ID中的一个,然后传递索引来切片数字列表中给定索引处的总和。希望能够做类似这样的事情:
hr_total = stats[year=2001, idx=3]
其中,索引 3 对应于检索到的数字列表中的第三列。
2、解决方案
有以下几种解决方案:
- 解决方案一:将数据放入 SQLite 中,并使用其关系引擎来完成这项工作。甚至可以创建一个内存数据库,而无需触及磁盘。
- 解决方案二:查阅有关数据仓储的任何书籍。学习星型模式设计。具有多个维度:年、球员、球队。有一个事实:得分。希望有一个这样的结构。然后希望创建一个这样的维度索引集。
years = collections.defaultdict(list)
players = collections.defaultdict(list)
teams = collections.defaultdict(list)
事实表可以是这个 collections.namedtuple。可以像这样使用它。
class ScoreFact(object):
def __init__(self, year, player, team, score):
self.year = year
self.player = player
self.team = team
self.score = score
years[self.year].append(self)
players[self.player].append(self)
teams[self.team].append(self)
现在可以找到给定维度值中的所有项。它是一个附加到维度值上的简单列表。year[‘2001’] 是给定年份的所有得分。player[‘SEA’] 是给定球员的所有得分。等等。可以简单地使用 sum() 将它们相加。多维查询类似于这样。
[x for x in players['SEA'] if x.year == '2001']
- 解决方案三:语法 stats[year=2001, idx=3] 是无效的 Python,无法用那些方括号和“关键字参数”让它工作;需要有函数或方法调用才能接受关键字参数。因此,假设将其变成一个函数,像这样调用 wells(stats, year=2001, idx=3)。想象 idx 参数是强制性的(给定调用这是非常奇怪的,但是没有给出任何可能意味着省略 idx 的迹象),并且必须存在 year、playerid 和 teamid 中的恰好一个。使用当前的数据结构,已经可以实现 wells:
def wells(stats, year=None, playerid=None, teamid=None, idx=None):
if idx is None: raise ValueError('idx must be specified')
specifiers = [(i, x) for x in enumerate((year, playerid, teamid)) if x is not None]
if len(specifiers) != 2:
raise ValueError('Exactly one of year, playerid, teamid, must be given')
ikey, keyv = specifiers[0]
return sum(v[idx] for k, v in stats.iteritems() if k[ikey] == keyv)
当然,这是 stats 大小的 O(N)——它必须检查其中的每个条目。请使用此简单实现作为基准来衡量正确性和性能。另一种解决方案(使用起来要快得多,但需要花费大量时间准备)是在 stats 旁边放置三个列表字典(分别用于 year、playerid、teamid),每个条目都表示(或复制,但认为按完整键指示可能就足够了)所有与该 ikey / keyv 对匹配的 stats条目。但目前尚不清楚是否可能为时过早地实现,因此请先尝试使用简单的想法!-)