【问题标题】:Relational data structure in pythonpython中的关系数据结构
【发布时间】:2015-04-14 20:04:38
【问题描述】:

我正在寻找一种在 python 中类似于 SQL 关系表的数据结构,或者如果不存在的话,可以提供一些实现一个的提示。从概念上讲,数据结构是一组对象(任何对象),它支持高效的查找/过滤(可能使用类似 SQL 的索引)。

例如,假设我的对象都有属性ABC,我需要过滤这些属性,因此我定义数据应该由它们索引。对象可能包含许多不用于过滤的其他成员。数据结构应支持与SELECT <obj> from <DATASTRUCTURE> where A=100 等效的操作(BC 相同)。还应该可以按多个字段 (where A=100 and B='bar') 进行过滤。

要求是:

  1. 应该支持大量项目 (~200K)。这些项目必须是对象本身,而不是它们的某些扁平化版本(排除了sqlite 和可能的pandas)。
  2. 插入应该很快,应该避免重新分配内存(这几乎排除了pandas
  3. 应支持简单过滤(如上例),它必须比O(len(DATA)) 更有效,即避免“全表扫描”。

这样的数据结构存在吗?


请不要建议使用 sqlite。我需要反复转换对象->行和行->对象,这既费时又麻烦,因为我的对象不一定是扁平的。

另外,请不要建议使用 pandas,因为重复插入行太慢,因为它可能需要频繁重新分配。

【问题讨论】:

    标签: python sql indexing data-structures relational


    【解决方案1】:

    只要您在 (a,b,c) 上没有任何重复项,您就可以将 dict 子类化,输入由元组 (a,b,c) 索引的对象,并定义您的过滤方法(可能生成器)返回所有符合您的条件的条目。

    class mydict(dict):
        def filter(self,a=None, b=None, c=None):
            for key,obj in enumerate(self):
                if (a and (key[0] == a)) or not a:
                    if (b and (key[1] == b)) or not b:
                        if (c and (key[2] == c)) or not c:
                            yield obj
    

    这是一个丑陋且非常低效的例子,但你明白了。我确信在itertools 或其他东西中有更好的实现方法。

    编辑:

    我一直在想这个。我昨晚玩弄了它,想出了将对象存储在列表中并按所需的键字段存储索引的字典。通过获取所有指定条件的索引的交集来检索对象。像这样:

    objs = []
    aindex = {}
    bindex = {}
    cindex = {}
    
    def insertobj(a,b,c,obj):
        idx = len(objs)
        objs.append(obj)
        if a in aindex:
            aindex[a].append(idx)
        else:
            aindex[a] = [idx]
    
        if b in bindex: 
            bindex[b].append(idx)
        else:
            bindex[b] = [idx]
    
        if c in cindex:
            cindex[c].append(idx)
        else :
            cindex[c] = [idx]
    
    def filterobjs(a=None,b=None,c=None):
        if a : aset = set(aindex[a])
        if b : bset = set(bindex[b])
        if c : cset = set(cindex[c])
        result = set(range(len(objs)))
        if a and aset : result = result.intersection(aset)
        if b and bset : result = result.intersection(bset)
        if c and cset : result = result.intersection(cset)
        for idx in result:
            yield objs[idx]
    
    class testobj(object):
        def __init__(self,a,b,c):
            self.a = a
            self.b = b
            self.c = c
    
        def show(self):
            print ('a=%i\tb=%i\tc=%s'%(self.a,self.b,self.c))
    
    if __name__ == '__main__':
        for a in range(20):
            for b in range(5):
                for c in ['one','two','three','four']:
                    insertobj(a,b,c,testobj(a,b,c))
    
        for obj in filterobjs(a=5):
            obj.show()
        print()
        for obj in filterobjs(b=3):
            obj.show()
        print()
        for obj in filterobjs(a=8,c='one'):
            obj.show()
    

    它应该相当快,尽管对象在列表中,但它们可以通过索引直接访问。 “搜索”是在散列字典上完成的。

    【讨论】:

    • @Martijn Pieters 在link 的问题上使用 fnmatch 为这个问题的匹配/选择/过滤方面提供了一个很好的例子。
    猜你喜欢
    • 2015-12-03
    • 1970-01-01
    • 2012-07-10
    • 2013-09-13
    • 2011-04-30
    • 1970-01-01
    • 2014-10-06
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多