【问题标题】:Delete duplicated of an object within a list删除列表中对象的重复项
【发布时间】:2018-07-19 04:33:34
【问题描述】:

我得到一个波形对象,定义如下:

class wfm:
    """Class defining a waveform characterized by:
        - A name
        - An electrode configuration
        - An amplitude (mA)
        - A pulse width (microseconds)"""

    def __init__(self, name, config, amp, width=300):
        self.name = name
        self.config = config
        self.amp = amp
        self.width = width

    def __eq__(self, other):
        return type(other) is self.__class__ and other.name == self.name and other.config == self.config and other.amp == self.amp and other.width == self.width

    def __ne__(self, other):
        return not self.__eq__(other)

通过解析,我得到一个名为波形的列表,其中包含 770 个 wfm 实例。有很多重复的,我需要删除它们。

我的想法是获取等效对象的 ID,将最大的 ID 存储在列表中,然后在弹出每个重复项的同时从末尾循环所有波形。

代码:

duplicate_ID = []
for i in range(len(waveforms)):
    for j in range(i+1, len(waveforms)):
        if waveforms[i] == waveforms[j]:
            duplicate_ID.append(waveforms.index(waveforms[j]))
            print ('{} eq {}'.format(i, j))

duplicate_ID = list(set(duplicate_ID)) # If I don't do that; 17k IDs

结果(感谢打印)我有没有出现在 ID 列表中的重复项,例如 750 是 763 的重复项(打印说明;也进行测试)但是这 2 个 ID 都没有出现在我的重复列表。

我很确定有一个比这种方法更好的解决方案(目前还不行),我很高兴听到它。感谢您的帮助!

编辑:更复杂的场景

我有一个更复杂的场景。我有 2 个课程,wfm(见上文)和 stim:

class stim:
    """Class defining the waveform used for a stimultion by:
        - Duration (milliseconds)
        - Frequence Hz)
        - Pattern of waveforms"""

    def __init__(self, dur, f, pattern):
        self.duration = dur
        self.fq = f
        self.pattern = pattern

    def __eq__(self, other):
        return type(other) is self.__class__ and other.duration == self.duration and other.fq == self.fq and other.pattern == self.pattern

    def __ne__(self, other):
        return not self.__eq__(other)

我解析我的文件以填充 dict: 范式。看起来是这样的:

paradigm[file name STR] = (list of waveforms, list of stimulations)

# example:
paradigm('myfile.xml') = ([wfm1, ..., wfm10], [stim1, ..., stim5])

再次,我想删除重复项,即我只想保留以下数据:

  • 波形相同
  • 和stim是一样的

例子:

file1 has 10 waveforms and file2 has the same 10 waveforms.
file1 has stim1 and stim2 ; file2 has stim3, sitm 4 and stim 5.

stim1 and stim3 are the same; so since the waveforms are also the same, I want to keep:
file1: 10 waveforms and stim1 and stim2
file2: 10 waveforms and stim 4 and stim5

相关性在我的脑海中有点混乱,所以我很难找到适合波形和刺激的存储解决方案以便轻松比较它们。如果你有任何想法,我会很高兴听到它。谢谢!

【问题讨论】:

  • 这与您的问题无关,但我认为您想将 width 设为默认参数,但将值 300 放置在错误的位置,对吗?
  • 如果您使用namedtuple 而不是class 会容易得多。 WFM = namedtuple('WFM', ['name', 'config', 'amp', 'width'])。然后在WFM 的实例列表上调用set() 将删除所有重复项。
  • 是的,感谢您对宽度的评论...您犯了一个小错误,因为它大部分时间都是不变的。我确实发现一些帖子看起来非常相似,但我还没有解决我的问题,这就是我发布这个的原因。谢谢Alex的回答,我试试!
  • @Mathieu 解决了问题吗?

标签: python class duplicates


【解决方案1】:

问题

.index 方法使用您重载的.__eq__ 方法。所以

waveforms.index(waveforms[j])

总是会在列表中找到第一个波形实例,其中包含与waveforms[j] 相同的属性。

w1 = wfm('a', {'test_param': 4}, 3, 2.0)
w2 = wfm('b', {'test_param': 4}, 3, 2.0)
w3 = wfm('a', {'test_param': 4}, 3, 2.0)

w1 == w3  # True
w2 == w3  # False

waveforms = [w1, w2, w3]
waveforms.index(waveforms[2]) == waveforms.index(waveforms[0]) == 0  # True

解决方案

不可变

如果您不可变地执行此操作,则不需要存储列表索引:

key = lambda w: hash(str(vars(w)))
dupes = set()
unique = [dupes.add(key(w)) or w for w in waveforms if key(w) not in dupes]

unique == [w1, w2]  # True

可变

key = lambda w: hash(str(vars(w)))
seen = set()
idxs = [i if key(w) in seen else seen.add(key(w)) for i, w in enumerate(waveforms)]

for idx in filter(None, idxs[::-1]):
    waveforms.pop(idx)

waveforms == [w1, w2]  # True

大 O 分析

在编写算法时考虑大的 O 复杂性是一个好习惯(尽管优化应该以牺牲可读性为代价仅在需要时)。在这种情况下,这些解决方案更具可读性,并且也是大 O 最优的。

由于双 for 循环,您的初始解决方案是 O(n^2)。

提供的两种解决方案都是 O(n)。

【讨论】:

  • 从您的操作来看,我遇到了一个非常相似的问题;我无法解决它......你介意看看编辑吗?
猜你喜欢
  • 2017-06-23
  • 2011-04-24
  • 2021-12-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-01-08
  • 1970-01-01
相关资源
最近更新 更多