Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/358.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 用于在内存中维护表格数据的数据结构?_Python_Data Structures - Fatal编程技术网

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

Python 用于在内存中维护表格数据的数据结构?,python,data-structures,Python,Data Structures,我的场景如下:我有一个在程序中广泛使用的数据表(少数字段,不到100行)。我还需要将这些数据持久化,所以我将其保存为CSV并在启动时加载。我选择不使用数据库,因为每一个选项(甚至SQLite)对于我的卑微要求来说都是多余的(而且-我希望能够以一种简单的方式离线编辑值,没有什么比记事本更简单的了) 假设我的数据如下所示(在文件中是逗号分隔的,没有标题,这只是一个示例): 注: 行可以是写入文件的“真实”值,也可以只是表示行号的自动生成值。无论哪种方式,它都存在于内存中 名称是唯一的 我对数据所做的

我的场景如下:我有一个在程序中广泛使用的数据表(少数字段,不到100行)。我还需要将这些数据持久化,所以我将其保存为CSV并在启动时加载。我选择不使用数据库,因为每一个选项(甚至SQLite)对于我的卑微要求来说都是多余的(而且-我希望能够以一种简单的方式离线编辑值,没有什么比记事本更简单的了)

假设我的数据如下所示(在文件中是逗号分隔的,没有标题,这只是一个示例):

注:

  • 行可以是写入文件的“真实”值,也可以只是表示行号的自动生成值。无论哪种方式,它都存在于内存中
  • 名称是唯一的
  • 我对数据所做的事情:

  • 根据ID(迭代)或名称(直接访问)查找行
  • 根据多个字段以不同的顺序显示表格:我需要对其进行排序,例如按优先级和年份排序,或按年份和优先级排序,等等
  • 我需要根据一组参数计算实例,例如,1997年到2002年之间有多少行具有其年份,或者1998年有多少行且优先级>2,等等
  • 我知道这是SQL的“呐喊”

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

    行列表列表:

    a = []
    a.append( [1, "Cat", 1998, 1] )
    a.append( [2, "Fish", 1998, 2] )
    a.append( [3, "Dog", 1999, 1] )
    ...
    
    列列表列表(显然会有一个用于添加行等的API):

    列列表字典(可以创建常量来替换字符串键):

    键为元组的字典(行、字段):

    我相信还有其他方法。。。然而,当涉及到我的需求(复杂的排序和计数)时,每种方法都有缺点


    推荐的方法是什么

    编辑:


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

    我个人会使用行列表列表。因为每一行的数据总是以相同的顺序排列,所以只需访问每个列表中的元素,就可以轻松地按任何列进行排序。您还可以轻松地根据每个列表中的特定列进行计数,并进行搜索。它基本上和二维阵列一样接近

    实际上,这里唯一的缺点是您必须知道数据的顺序,如果您更改了顺序,则必须更改搜索/排序例程以匹配

    你可以做的另一件事是列出字典

    rows = []
    rows.append({"ID":"1", "name":"Cat", "year":"1998", "priority":"1"})
    
    这将避免需要知道参数的顺序,因此您可以查看列表中的每个“年”字段。

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

    connection = sqlite3.connect(':memory:')
    
    然后,您可以使用SQLite的所有功能在内存中创建/删除/查询/更新表,完成后不会留下任何文件。而在Python2.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
    
    >lod=[]
    >>>填充\u lod(lod、csv\u fp)
    >>> 
    >>>pprint(查找\u lod(lod,行=1))
    {'Name':'Cat','Priority':'1','Row':'1','Year':'1998'}
    >>>pprint(lookup_lod(lod,Name='Aardvark'))
    {'Name':'Aardvark','Priority':'1','Row':'4','Year':'2000'}
    >>>pprint(查询详细程度(详细程度,排序关键字=('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(查询lod(lod,排序键=('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'}]
    >>>打印len(查询lod(lod,lambda r:1997>打印len)(查询lod(lod,lambda r:int(r['Year'])==1998,int(r['Priority'])>2))
    0
    

    就我个人而言,我更喜欢SQLite版本,因为它更好地保留了您的类型(在Python中没有额外的转换代码),并且易于扩展以适应未来的需求。但是,我对SQL非常熟悉,所以YMMV。

    首先,考虑到您有一个复杂的数据检索场景,您确定即使SQLite也有过多的功能吗

    您将得到一个临时的、非正式指定的、充满bug的、缓慢的SQLite的一半的实现

    你说,选择一个数据结构会影响一个或多个搜索、排序或计数,这是非常正确的,因此,如果性能是最重要的,并且数据是恒定的,那么你可以考虑为不同的目的而拥有不止一个结构。


    最重要的是,测量哪些操作更常见,并确定哪种结构最终成本更低。

    有一个表类,其行是dict或更好的行对象列表

    在表中,不要直接添加行,而是使用一种方法来更新一些查找映射,例如名称 如果不按顺序添加行或id不连续,也可以使用idMap e、 g


    我知道一个很老的问题,但是

    熊猫数据帧似乎是这里的理想选择

    F
    connection = sqlite3.connect(':memory:')
    
    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()
    
    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
    
    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'})
    
    from BD_XML import Tabla
    
    Table = Tabla('Animals') 
    
    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
    
    file = os.path.abspath(os.path.join(os.path.dirname(__file__), 'Animals.xml'))
    Table.exportar_xml()
    Table.escribir_xml(file)
    
    Table.importar_xml(file, tipo='archivo')
    #archivo means file
    
    #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 >= nmax: break
    print(Table)
    
    if row.pos == 2: