从容器类中删除元素

时间:2020-04-20 06:41:35

标签: python-3.x class

在下面的示例中,我无法为类__delitem__定义Container或类似方法。我该如何纠正?谢谢。

import numpy as np
import pandas as pd

class XLData(object):
    def __init__(self, name):
        self.name = name
        self.data = pd.DataFrame({self.name: list("ASDF" * 2),
                                  'x': np.random.randint(1, 100, 8) })
    def __repr__(self):
        return repr(self.data.head(2))

class Container(object):
    def __init__(self):
        self.counter = 0
        self.items = []
    def append(self, item):
        self.counter += 1
        self.items = self.items + [item]
    def __delitem__(self, name):
        for c in self.items:
            print("element name:{}, to delete:{}".format(c.name, name))
            if c.name == name:
                pass #!
                #del c
    def __iter__(self):
        for c in self.items:
            yield c

a = XLData('a')
b = XLData('b')
c = XLData('c')

dl = Container()
dl.append(a)
dl.append(b)
dl.append(c)
del dl['b']

for c in dl:
    print(c)
# 'b' is still in ..

5 个答案:

答案 0 :(得分:2)

最好不要在循环本身中修改要循环的数组。因此,只需选择项目的索引并将其删除即可。

class Container(object):
    def __init__(self):
        self.counter = 0
        self.items = {}                # create a dict!
    def append(self, item):
        self.counter += 1
        self.items[item.name] = item   # add items to it, keyed under their names
    def __delitem__(self, name):
        del self.items[name]           # this becomes *really* simple, and efficient
    def __iter__(self):
        for c in self.items.values:    # loop over the dict's values to the items
            yield c #

答案 1 :(得分:1)

您似乎已经知道,鉴于代码的注释,您无法在循环中执行del c,因为这只会暂时从函数的本地名称空间中删除c变量,而不会完全不更改列表结构。

有几种方法可以使它起作用。

一个想法是在循环列表中的值时使用enumerate,这样当您需要从列表中删除项目时,手头就有索引:

for i, item in enumerate(self.items):
    if item.name == name:
        del self.items[i]
        return

请注意,删除项目后我立即从函数返回。如果列表中可能同时存在多个具有相同名称的项目,则可能不是您想要的,但是此代码无法正确处理这种情况,因为一旦从列表中删除项目,迭代将无法正常进行(它可以让您继续迭代,但是会跳过一个值)。

一个更好的选择可能是使用列表理解来重建列表,使其仅包含要保留的值。

self.items = [item for item in self.items if item.name != name]

这很简洁,无论您要删除多少个名称,它都可以使用!

以上两种方法共有的一个缺点是,对于大型列表而言,它们的运行速度相当慢。他们需要遍历所有项目,他们无法提前告知要删除的项目存储在何处。一种替代方法是使用词典而不是列表来存储项目。如果您将商品名称用作键,则可以非常高效地查找它们。

这是一个实现的方法,尽管它只允许一个项目具有任何给定的名称(添加另一个将替换第一个):

class Container(object):
    def __init__(self):
        self.counter = 0
        self.items = {}                # create a dict!
    def append(self, item):
        self.counter += 1
        self.items[item.name] = item   # add items to it, keyed under their names
    def __delitem__(self, name):
        del self.items[name]           # this becomes *really* simple, and efficient
    def __iter__(self):
        for c in self.items.values():    # loop over the dict's values to the items
            yield c

答案 2 :(得分:1)

您实现它的方式,对于del之类的操作来说将会很慢。并且,如果您想添加其他通过名称返回对象的方法,例如__getitem__(),则通过遍历列表进行查找会很慢。您可能希望使用字典将XLData对象保存在Container内部。而且,由于Python的数据对象都具有length属性,因此您无需保留它们的数量。

class Container(object): # Python 3 doesn't require 'object' in class decls.
    def __init__(self):
        self._items = {}

    def add(self, item):
        # self._items.append(item) # Why create a new list each time. 
                                   # Just append. 
        self._items[item.name] = item

    def __len__(self):
        return len(self._items)

    def __getitem__(self, name):
        return self._items[name]

    def __delitem__(self, name):
        del self._items[name]      # Simple.

    def __iter__(self):
        for c in self._items.values():
            yield c

使用dict可以同时获得列表和字典的好处:通过名称快速访问以及对项进行迭代等等。dict跟踪键和键的顺序。项目已添加。如果确实需要单独的列表来进行排序和迭代,则可能有不止一种数据类型可以保存所包含对象的信息。您只需要同步dictlist

想一想,如果您希望自己的班级支持sort()操作,甚至只需要一点点创造力,甚至可以对没有列表的字典进行排序。

def sort(self, key=None):
    self._items = {k: v for k, v in sorted(self._items.items(), key=key)}

我想我现在太过分了=)

答案 3 :(得分:1)

最好不要在循环本身中修改要循环的数组。因此,只需选择项目的索引并将其删除即可。

def __delitem__(self, name):
    idx = -1
    found = False
    for c in self.items:
        idx += 1
        print("element name:{}, to delete:{}".format(c.name, name))
        if c.name == name:
            found = True
            break
    if found:
        del self.items[idx]

答案 4 :(得分:1)

替代方法,将列表过滤器选项与def delitem 方法中的对象attr条件一起使用

import numpy as np
import pandas as pd


class XLData(object):
    def __init__(self, name):
        self.name = name
        self.data = pd.DataFrame({self.name: list("ASDF" * 2),
                                  'x': np.random.randint(1, 100, 8)})

    def __repr__(self):
        return repr(self.data.head(2))


class Container(object):
    def __init__(self):
        self.counter = 0
        self.items = []

    def append(self, item):
        self.counter += 1
        self.items = self.items + [item]

    def __delitem__(self, name):
        self.items = [x for x in self.items if x.name != name]

    def __iter__(self):
        for c in self.items:
            yield c


a = XLData('a')
b = XLData('b')
c = XLData('c')

dl = Container()
dl.append(a)
dl.append(b)
dl.append(c)

del dl['b']

for c in dl:
    print(c)

输出

   a   x
0  A  13
1  S  97
   c   x
0  A  91
1  S  17