当前位置: 首页 > 面试题库 >

用于在内存中维护表格数据的数据结构?

黄鸣
2023-03-14
问题内容

我的情况如下:我有一个数据表(少数字段,少于一百行),该数据表在程序中广泛使用。我还需要这些数据具有持久性,因此我将其另存为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

笔记:

  1. 行可以是写入文件的“实际”值,也可以是代表行号的自动生成的值。无论哪种方式,它都存在于内存中。
  2. 名称是唯一的。

我对数据所做的事情:

  1. 根据ID(迭代)或名称(直接访问)查找一行。
  2. 根据多个字段以不同的顺序显示表格:我需要对表格进行排序,例如,按优先级排序,然后按年份排序,或者按年份排序,然后按优先级排序,依此类推。
  3. 我需要根据参数集对实例进行计数,例如,1997年至2002年之间的年份有多少行,或者1998年的优先级> 2等有多少行。

我知道SQL的这种“呼声” …

我试图找出什么是数据结构的最佳选择。以下是我看到的几种选择:

行列表列表:

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

列列表的列表(显然会有add_row等的API):

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]

键为(Row,Field)元组的字典:

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
...

而且我敢肯定还有其他方法…但是,在满足我的要求(复杂的订购和计数)时,每种方法都有缺点。

推荐的方法是什么?

编辑:

需要澄清的是,性能对我而言不是主要问题。由于表太小,我相信几乎每个操作都将在毫秒范围内,这对我的应用程序来说不是问题。


问题答案:

在内存中有一个需要查询,排序和任意聚合的“表”确实确实需要SQL。您说您尝试过SQLite,但是您是否意识到SQLite可以使用仅内存数据库?

connection = sqlite3.connect(':memory:')

然后,您可以使用SQLite的所有功能在内存中创建/删除/查询/更新表,完成后不留文件。从Python
2.5开始,sqlite3它在标准库中,因此它并不是真正的“滥杀滥伤” 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来说很满意。



 类似资料:
  • 到目前为止,我们已经讨论了为了实现文件系统而需要存在于硬盘上的数据结构。 在这里,我们将了解要实现文件系统需要存在于内存中的数据结构。 内存数据结构用于文件系统管理以及通过缓存提高性能。 该信息在安装时间加载并在弹出时丢弃。 1. 内存安装表 内存中安装表包含正在安装到系统的所有设备的列表。 每当连接维护到设备时,其输入将在安装表中完成。 2. 内存目录结构缓存 这是CPU最近访问的目录列表。列表

  • 问题内容: 前言:前几天,我在考虑为新应用程序使用新的数据库结构,并意识到我们需要一种有效地存储历史数据的方法。我想让其他人看一看,看看这种结构是否有任何问题。我意识到这种存储数据的方法很可能以前就已经发明了(我几乎可以肯定已经有了),但是我不知道它是否有名称,并且我尝试过的一些Google搜索都没有产生任何结果。 问题:假设您有一个订单表,并且订单与下订单的客户的客户表相关。在正常的数据库结构中

  • 我正在用Python实现一个Trie。到目前为止,我遇到了两种不同的方法来实现它: -存储字符 -存储单词结尾(true或false) -存储具有当前前缀的单词数 我们派生出这本词典: 哪一种是高效的、标准的数据结构,既能有效地存储内存,又能快速地进行字的大数据集上的遍历和其他trie操作?

  • 有的时候,你需要对仓库进行清理 - 使它的结构变得更紧凑,或是对导入的仓库进行清理,或是恢复丢失的内容。 这个小节将会介绍这些情况中的一部分。 维护 Git 会不定时地自动运行一个叫做 “auto gc” 的命令。 大多数时候,这个命令并不会产生效果。 然而,如果有太多松散对象(不在包文件中的对象)或者太多包文件,Git 会运行一个完整的 git gc 命令。 “gc” 代表垃圾回收,这个命令会做

  • 主要内容:程序员的幽默计算机要处理的信息是多种多样的,如数字、文字、符号、图形、音频、视频等,这些信息在人们的眼里是不同的。但对于计算机来说,它们在内存中都是一样的,都是以二进制的形式来表示。 要想学习编程,就必须了解二进制,它是计算机处理数据的基础。 内存条是一个非常精密的部件,包含了上亿个电子元器件,它们很小,达到了纳米级别。这些元器件,实际上就是电路;电路的电压会变化,要么是 0V,要么是 5V,只有这两种电压。

  • 数据结构和算法是过去 50 年来最重要的发明之一,它们是软件工程师需要了解的基础工具。但是在我看来,这些话题的大部分书籍都过于理论,过于庞大,也是“自底向上”的