如何提高我的嵌套列表的索引效率?

0 投票
2 回答
509 浏览
提问于 2025-04-16 16:47

我想把数据存储在一个列表的列表里,也就是说,每个样本都有很多相关的信息,这些信息放在一个列表里,然后把很多这样的列表放在一个大列表里。到目前为止,我的代码是:

#!/usr/bin/env python

from operator import itemgetter # For sorting

class XaDatum (object):

    fields = {'name':0, 'ki':1, 'amt':2, 'rep': 3, 'stage':4, 'variety':5, 
              'date':6, 'comments':7}

    def __init__(self, name, ki, amt, rep=None, stage=None, variety=None, 
                 date=None, comments = None):
        for item in (name, rep, stage, variety, date, comments):
            if item is not None:
                item = str(item)
        ki = int(ki)
        amt = float(amt)
        self.datum = [name, ki, amt, rep, stage, variety, date, comments]

    def __getitem__(self, key):
        return self.datum[self.fields[key]]

    def copy(self):
        return XaDatum(self['name'], self['ki'], 
                          self['amt'], self['rep'], 
                          self['stage'], self['variety'], 
                          self['date'], self['comments'])

    def __setitem__(self, key, item): 
        if key in ['name', 'rep', 'stage', 'variety', 'date', 'comments']:
            item = str(item)
        if key == 'ki':
            item = int(item)
        if key == 'amt':
            item = float(item)
        self.datum[self.fields[key]] = item

    def __str__(self):
        return repr(self.datum)

    def show(self):
        print("{0}  {1}  {2}  {3}  {4}  {5}  {6}  {7}".format(
                self['name'], self['ki'], self['amt'], self['rep'],
                self['stage'], self['variety'], self['date'], 
                self["comments"]))


class XaData (object):

    def __init__(self):
        self.data = []
        self.count = 0

    def __getitem__(self, index):
        return self.data[index]

    def __str__(self):
        return repr(self.data)

    def append(self, name, ki, amt, rep=None, stage=None, variety=None, 
               date=None, comments=None):
        self.data.append(
            XaDatum(name, ki, amt, rep, stage, variety, date, comments))
        self.count += 1

    def show(self):
        for i in self.data:
            i.show()

    def copy(self):
        returnme = XaData()
        for item in self:
            returnme.data.append(item.copy())
        return returnme

    # Result points to the same memory! Changes to the returned
    # znoselonglist will result in changes to the original!
    def filter(self, inverse=False, min=-float('Inf'), max=float('Inf'), 
               ki_min=-float('Inf'), ki_max=float('Inf'), rep=None, stage=None,
               variety=None, date=None, comment=None):
        returnme = XaData()
        for item in self.data:
            match = ((item['amt'] >= min)
                     and (item['amt'] <= max)
                     and (item['ki'] >= ki_min)
                     and (item['ki'] <= ki_max)
                     and (rep is None or item['rep'] in rep)
                     and (stage is None or item['stage'] in stage)
                     and (variety is None or item['variety'] in variety)
                     and (date is None or item['date'] in date)
                     and (comment is None or item['comment'] in comment))
            if match ^ inverse:
                returnme.data.append(item)
        return returnme

    def sort(self, *args):
        if len(args) == 0:
            args = ('name', 'ki')
        self.data = sorted(self.data, key=itemgetter(*args))

    def unique(self, key):
        key_list = [item[key] for item in self.data]
        return sorted(list(set(key_list)))

    def unique_kis(self):
        kilist = [item['ki'] for item in self.data]
        return sorted(list(set(kilist)))

    def unique_names(self):
        namelist = [item['name'] for item in self.data]
        return sorted(list(set(namelist)))


if __name__ == "__main__":

    da = XaData()
    da.append('x00', 35, 501, stage='B', variety='V1')
    da.append('x01', 40, 309, stage='D', variety='V2')
    da.append('x02', 37, 450, stage='D', variety='V1')
    da.append('x03', 35, 470, stage='A', variety='V2')
    da.append('x04', 40, 378, stage='B', variety='V1')
    da.append('x05', 45, 770, stage='A', variety='V2')

如果我运行这个代码,我可以做到:

In [1]: da.show()
x00  35  501.0  None  B  V1  None  None
x01  40  309.0  None  D  V2  None  None
x02  37  450.0  None  D  V1  None  None
x03  35  470.0  None  A  V2  None  None
x04  40  378.0  None  B  V1  None  None
x05  45  770.0  None  A  V2  None  None

In [2]: daf = da.filter(variety='V1')

In [3]: daf.show()
x00  35  501.0  None  B  V1  None  None
x02  37  450.0  None  D  V1  None  None
x04  40  378.0  None  B  V1  None  None

In [4]: daf[0]['amt'] *= 0.2

In [5]: daf.show()
x00  35  100.2  None  B  V1  None  None
x02  37  450.0  None  D  V1  None  None
x04  40  378.0  None  B  V1  None  None

但是我不能做到:

In [6]: daf[:]['amt'] *= 0.2
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)

/home/nathan/work/simo_znose/<ipython console> in <module>()

TypeError: list indices must be integers, not str

所以我的问题是,怎么才能让切片(slicing)工作?或者说,有没有现成的数据类型可以实现我想要的功能?

提前谢谢你们!

Nathan

2 个回答

1

看起来切片功能是正常工作的。daf[:] 返回的是 daf.data 的一个副本,而 daf.data 是一个列表——所以当你试图用 'amt' 来索引这个结果时会出错,因为你不能用字符串来索引一个列表。

再重复一下poke的评论,daf[:]['amt'] 你想要实现的功能不太清楚。看起来你是想修改一个副本中所有XaDatum对象的 'amt'。但这真的是你想要的吗?如果是的话,你需要修改 XaData.__setitem__(为了完整性,也要修改 XaData.__getitem__)来接受字符串索引。

你还需要修改 XaData.__getitem__,让切片返回一个新的 XaData 对象,而不是一个新的 list 对象。其实你应该这么做——无论如何,这都是预期的切片行为。

如果你打算编写自定义的 __getitem____setitem__ 方法,了解一下 切片对象 可能会对你有帮助。

1

你可以很方便地用NumPy的记录数组来处理这样的表格。NumPy在Python中是进行数组操作的事实标准。

你也可以考虑使用数据库表,比如通过SQLite来实现。

撰写回答