13

假设我没有超过一两打具有不同属性的对象,例如:

UID、名称、值、颜色、类型、位置

我希望能够调用 Location = "Boston" 或 Type = "Primary" 的所有对象。经典的数据库查询类型的东西。

大多数表解决方案(pytables、*sql)对于这么小的数据集来说真的是过大了。我是否应该简单地遍历所有对象并为每个数据列创建一个单独的字典(在添加新对象时向字典添加值)?

这将创建这样的字典:

{'Boston' : [234, 654, 234], 'Chicago' : [324, 765, 342] } - 这 3 位数字条目代表诸如 UID 之类的东西。

正如你所看到的,查询这个会有点痛苦。

有什么替代方案的想法吗?

4

3 回答 3

14

对于小的关系问题,我喜欢使用 Python 的内置sets

对于 location = 'Boston' OR type = 'Primary' 的示例,如果您有以下数据:

users = {
   1: dict(Name="Mr. Foo", Location="Boston", Type="Secondary"),
   2: dict(Name="Mr. Bar", Location="New York", Type="Primary"),
   3: dict(Name="Mr. Quux", Location="Chicago", Type="Secondary"),
   #...
}

您可以WHERE ... OR ...像这样进行查询:

set1 = set(u for u in users if users[u]['Location'] == 'Boston')
set2 = set(u for u in users if users[u]['Type'] == 'Primary')
result = set1.union(set2)

或者只有一种表达方式:

result = set(u for u in users if users[u]['Location'] == 'Boston'
                              or users[u]['Type'] == 'Primary')

您还可以使用itertools中的函数来创建相当有效的数据查询。例如,如果您想做类似于 a 的事情GROUP BY city

cities = ('Boston', 'New York', 'Chicago')
cities_users = dict(map(lambda city: (city, ifilter(lambda u: users[u]['Location'] == city, users)), cities))

您还可以手动构建索引(构建dict映射位置到用户 ID)以加快速度。如果这变得太慢或太笨重,那么我可能会切换到sqlite,它现在包含在 Python (2.5) 标准库中。

于 2009-09-24T14:21:30.040 回答
6

我不认为 sqlite 会“矫枉过正”——它自 2.5 以来就带有标准 Python,因此无需安装任何东西,它可以在内存或本地磁盘文件中创建和处理数据库。真的,怎么可能更简单……?如果您想要内存中的所有内容,包括初始值,并且想要使用 dicts 来表达这些初始值,例如...:

import sqlite3

db = sqlite3.connect(':memory:')
db.execute('Create table Users (Name, Location, Type)')
db.executemany('Insert into Users values(:Name, :Location, :Type)', [
   dict(Name="Mr. Foo", Location="Boston", Type="Secondary"),
   dict(Name="Mr. Bar", Location="New York", Type="Primary"),
   dict(Name="Mr. Quux", Location="Chicago", Type="Secondary"),
   ])
db.commit()
db.row_factory = sqlite3.Row

现在你的内存中的小“db”已经准备好了。当然,在磁盘文件中创建数据库和/或从文本文件、CSV 等读取初始值并不难。

查询特别灵活、简单、甜美,例如,你可以随意混合字符串插入和参数替换......:

def where(w, *a):
  c = db.cursor()
  c.execute('Select * From Users where %s' % w, *a)
  return c.fetchall()

print [r["Name"] for r in where('Type="Secondary"')]

发出[u'Mr. Foo', u'Mr. Quux'],就像更优雅但等效的一样

print [r["Name"] for r in where('Type=?', ["Secondary"])]

你想要的查询只是:

print [r["Name"] for r in where('Location="Boston" or Type="Primary"')]

等等。说真的——有什么不喜欢的?

于 2009-09-24T15:11:08.403 回答
2

如果它真的是少量数据,我不会为索引而烦恼,可能只是编写一个辅助函数:

users = [
   dict(Name="Mr. Foo", Location="Boston", Type="Secondary"),
   dict(Name="Mr. Bar", Location="New York", Type="Primary"),
   dict(Name="Mr. Quux", Location="Chicago", Type="Secondary"),
   ]

def search(dictlist, **kwargs):
   def match(d):
      for k,v in kwargs.iteritems():
         try: 
            if d[k] != v: 
               return False
         except KeyError:
            return False
      return True

   return [d for d in dictlist if match(d)] 

这将允许像这样漂亮的查询:

result = search(users, Type="Secondary")
于 2009-09-24T14:31:39.960 回答