存储表格数据在内存中的数据结构?

我的剧本如下所示:我有一个数据表 /几个字段,小于一百条线/, 我在我的程序中广泛使用。 我还需要这些数据常量,所以我保护它们 CSV 并在开始时下载。 我不愿不要使用数据库,因为每个参数 /甚至 SQLite/ 对我的谦虚要求是多余的 /此外,我希望能够以简单的方式脱机编辑值,并且没有比记事本更容易。/.

假设我的数据看起来像这样 /在文件中,他们用逗号除以标题,这只是一个插图/:


Row | Name | Year | Priority
------------------------------------
1 | Cat | 1998 | 1
2 | Fish | 1998 | 2
3 | Dog | 1999 | 1
4 | Aardvark | 2000 | 1
5 | Wallaby | 2000 | 1
6 | Zebra | 2001 | 3


记录:

字符串可以是值。 "real", 录制到文件,或简单地自动生成表示行号的值。 在任何情况下,它都存在于内存中。

名字是唯一的。

我对数据做了什么:

基于两个搜索行 ID /迭代/, 任何一个名字 /直接访问/.

基于多个字段在不同的订单中显示表:我需要对其进行排序,例如优先级,然后按年或逐年,然后在优先级等。

例如,我需要基于参数集计算实例,例如,两行之间有多少行 1997 和 2002 年份或数量是多少 1998 年份和优先权 > 2 等等。

我知道 "cries" 为了 SQL...

我正试图了解数据结构的最佳选择。 以下是我看到的一些选择:

线条列表:


a = []
a.append/ [1, "Cat", 1998, 1] /
a.append/ [2, "Fish", 1998, 2] /
a.append/ [3, "Dog", 1999, 1] /
...


列列表列表 /显然,它会 API 为了 add_row 等等/:


a = []
a.append/ [1, 2, 3, 4, 5, 6] /
a.append/ ["Cat", "Fish", "Dog", "Aardvark", "Wallaby", "Zebra"] /
a.append/ [1998, 1998, 1999, 2000, 2000, 2001] /
a.append/ [1, 2, 1, 1, 1, 3] /


列列表的词汇 /可以创建常量来替换字符串键/:


a = {}
a['ID'] = [1, 2, 3, 4, 5, 6]
a['Name'] = ["Cat", "Fish", "Dog", "Aardvark", "Wallaby", "Zebra"]
a['Year'] = [1998, 1998, 1999, 2000, 2000, 2001]
a['Priority'] = [1, 2, 1, 1, 1, 3]


词典用封面的键 /行,领域/:


Create constants to avoid string searching
NAME=1
YEAR=2
PRIORITY=3

a={}
a[/1, NAME/] = "Cat"
a[/1, YEAR/] = 1998
a[/1, PRIORITY/] = 1
a[/2, NAME/] = "Fish"
a[/2, YEAR/] = 1998
a[/2, PRIORITY/] = 2
...


而且我相信还有其他方式......但是,在我的索赔时,各方面都有其缺点 /复杂订单和计数/.

什么是推荐的方法?

EDIT:

为了澄清,表现对我来说不是一个主要问题。 由于表桌子如此之小,我相信几乎每个操作都将在毫秒乐队中,这不是我的应用程序的问题。
已邀请:

江南孤鹜

赞同来自:

可用性 "table" 在需要搜索的内存中,对排序和任意聚合确实需要 SQL. 你说你试过 SQLite, 但你明白了吗? SQLite 可以使用数据库 in-memory-only?


connection = sqlite3.connect/':memory:'/


那么你就可以 create/drop/query/update 内存中的表格包含所有功能 SQLite 完成后,没有任何文件。 as Python 2.5
sqlite3

位于标准库中,事实上它不是 "overkill" IMO.

以下是如何在数据库中创建和填写的示例:


import csv
import sqlite3

db = sqlite3.connect/':memory:'/

def init_db/cur/:
cur.execute/'''CREATE TABLE foo /
Row INTEGER,
Name TEXT,
Year INTEGER,
Priority INTEGER/'''/

def populate_db/cur, csv_fp/:
rdr = csv.reader/csv_fp/
cur.executemany/'''
INSERT INTO foo /Row, Name, Year, Priority/
VALUES /?,?,?,?/''', rdr/

cur = db.cursor//
init_db/cur/
populate_db/cur, open/'my_csv_input_file.csv'//
db.commit//


如果你真的不喜欢使用 SQL, 您可能会使用词典列表:


lod = [ ] # "list of dicts"

def populate_lod/lod, csv_fp/:
rdr = csv.DictReader/csv_fp, ['Row', 'Name', 'Year', 'Priority']/
lod.extend/rdr/

def query_lod/lod, filter=None, sort_keys=None/:
if filter is not None:
lod = /r for r in lod if filter/r//
if sort_keys is not None:
lod = sorted/lod, key=lambda r:[r[k] for k in sort_keys]/
else:
lod = list/lod/
return lod

def lookup_lod/lod, **kw/:
for row in lod:
for k,v in kw.iteritems//:
if row[k] != str/v/: break
else:
return row
return None


然后给出:


>>> lod = []
>>> populate_lod/lod, csv_fp/
>>>
>>> pprint/lookup_lod/lod, Row=1//
{'Name': 'Cat', 'Priority': '1', 'Row': '1', 'Year': '1998'}
>>> pprint/lookup_lod/lod, Name='Aardvark'//
{'Name': 'Aardvark', 'Priority': '1', 'Row': '4', 'Year': '2000'}
>>> pprint/query_lod/lod, sort_keys=/'Priority', 'Year'///
[{'Name': 'Cat', 'Priority': '1', 'Row': '1', 'Year': '1998'},
{'Name': 'Dog', 'Priority': '1', 'Row': '3', 'Year': '1999'},
{'Name': 'Aardvark', 'Priority': '1', 'Row': '4', 'Year': '2000'},
{'Name': 'Wallaby', 'Priority': '1', 'Row': '5', 'Year': '2000'},
{'Name': 'Fish', 'Priority': '2', 'Row': '2', 'Year': '1998'},
{'Name': 'Zebra', 'Priority': '3', 'Row': '6', 'Year': '2001'}]
>>> pprint/query_lod/lod, sort_keys=/'Year', 'Priority'///
[{'Name': 'Cat', 'Priority': '1', 'Row': '1', 'Year': '1998'},
{'Name': 'Fish', 'Priority': '2', 'Row': '2', 'Year': '1998'},
{'Name': 'Dog', 'Priority': '1', 'Row': '3', 'Year': '1999'},
{'Name': 'Aardvark', 'Priority': '1', 'Row': '4', 'Year': '2000'},
{'Name': 'Wallaby', 'Priority': '1', 'Row': '5', 'Year': '2000'},
{'Name': 'Zebra', 'Priority': '3', 'Row': '6', 'Year': '2001'}]
>>> print len/query_lod/lod, lambda r:1997 <= int/r['Year']/ <= 2002//
6
>>> print len/query_lod/lod, lambda r:int/r['Year']/==1998 and int/r['Priority']/ > 2//
0


就个人而言,我喜欢更多的版本 SQLite, 因为它更好地保留您的类型 /没有额外的转换代码 Python/ 它很容易满足未来的要求。 但再次,我完全满意 SQL, 以便 YMMV.

冰洋

赞同来自:

非常古老的问题,我知道,但......

A pandas DataFrame 似乎在这里是理想的选择。

http://pandas.pydata.org/panda ... .html
来自广告

二维尺寸变化,潜在的异质表格
标有轴的数据结构 /行和列/. 算术运算
行和列的对齐。 可以被认为是一个dicti
串联对象的容器。 主要数据结构 pandas

http://pandas.pydata.org/
/

郭文康

赞同来自:

我会亲自使用一行线列表。 由于每行的数据始终以相同的顺序,因此只需通过在每个列表中的每个列表中联系此项目即可轻松地对其进行排序。 您还可以轻松地计算每个列表中的特定列,以及搜索。 它基本上与阵列一样接近 2-d.

实际上,这里唯一的缺点是您需要在数据的情况下了解的是数据,如果更改此订单,则必须更改搜索过程/排序使他们匹配。

还有一件事你可以做到 - 这是一个词典列表。


rows = []
rows.append/{"ID":"1", "name":"Cat", "year":"1998", "priority":"1"}/


这将避免需要了解参数的顺序,因此您可以查看每个字段。 "year" 在列表中。

小明明

赞同来自:

首先,考虑到你有一个复杂的数据搜索脚本,你确定偶数sqlite是破坏吗?

最终,您将获得特殊,非正式的预定,完全错误,实现了一半的缓慢 SQLite, 派对
n's_Tenth_Rule[/url]
格林斯帕那 .

尽管如此,您是绝对正确的,说一个数据结构的选择将影响搜索,排序或计数,因此,如果性能至关重要,并且您的数据是常量的,则可以考虑使用多种结构进行不同目的。

首先,衡量哪些操作将更常见,并确定哪个结构最终将不到较少。

郭文康

赞同来自:

有一个类类,其线是对象列表 dict 或更好 row

在表中,请勿直接添加字符串,但是有一种方法可以更新多个搜索卡,例如名称
, 如果您没有按顺序添加行或 id 不一致,你也可以 idMap,
例如


class Table/object/:
def __init__/self/:
self.rows = []# list of row objects, we assume if order of id
self.nameMap = {} # for faster direct lookup for row by name

def addRow/self, row/:
self.rows.append/row/
self.nameMap[row['name']] = row

def getRow/self, name/:
return self.nameMap[name]


table = Table//
table.addRow/{'ID':1,'name':'a'}/

诸葛浮云

赞同来自:

我个人写道 lib 几乎所有这一切,最近,它被称为 BD_XML

由于其最根本的存在原因是作为一种转移数据的方式 XML 文件I. SQL 数据库。

它是用西班牙语写的 /如果它对编程语言很重要/, 但非常简单。


from BD_XML import Tabla


它定义了一个名为的对象 Tabla /桌子/, 它可以使用名称创建,以标识连接兼容数据库接口的预先创建的对象 pep-246.


Table = Tabla/'Animals'/


然后,您需要使用该方法添加列
agregar_columna

/add_column/, 可以采取不同的关键字参数:


campo

/场地/: 字段名称


tipo

/一种/: 存储的数据类型可能是类似的 'varchar' 和 'double' 或对象的名称 python, 如果您对导出后一个数据库不感兴趣。


defecto

/default/: 如果添加字符串时,请设置列的默认值。

还有其他人 3 但它们仅适用于数据库,实际上并不存在

喜欢:


Table.agregar_columna/campo='Name', tipo='str'/
Table.agregar_columna/campo='Year', tipo='date'/
#declaring it date, time, datetime or timestamp is important for being able to store it as a time object and not only as a number, But you can always put it as a int if you don't care for dates
Table.agregar_columna/campo='Priority', tipo='int'/


然后您使用操作员添加字符串 + = /或者 +, 如果要使用额外的字符串创建副本/


Table += /'Cat', date/1998,1,1/, 1/
Table += {'Year':date/1998,1,1/, 'Priority':2, Name:'Fish'}
#…
#The condition for adding is that is a container accessible with either the column name or the position of the column in the table


然后你可以生成 XML 并用文件写入文件
exportar_XML

/export_XML/ 和
escribir_XML

/write_XML/:


file = os.path.abspath/os.path.join/os.path.dirname/__file__/, 'Animals.xml'//
Table.exportar_xml//
Table.escribir_xml/file/


然后使用它会使用它
importar_XML

/import_XML/ 使用文件名并指示您使用该文件,而不是字符串文字:


Table.importar_xml/file, tipo='archivo'/
#archivo means file


先进的

这些是您可以使用该对象的方式。 Tabla 以态度 SQL.


#UPDATE <table> SET Name = CONCAT/Name,' ',Priority/, Priority = NULL WHERE id = 2
for row in Table:
if row['id'] == 2:
row['Name'] += ' ' + row['Priority']
row['Priority'] = None
print/Table/

#DELETE FROM <table> WHERE MOD/id,2/ = 0 LIMIT 1
n = 0
nmax = 1
for row in Table:
if row['id'] % 2 == 0:
del Table[row]
n += 1
if n &gt;= nmax: break
print/Table/


此示例假定列名称 'id'
但是你可以替换宽度 row.pos 为你的例子。


if row.pos == 2:


可以从网站下载文件:

https://bitbucket.org/WolfangT/librerias
</table></table>

要回复问题请先登录注册