Найти, какой объект не в списке, но с возможными дубликатами ... хитрый - PullRequest
0 голосов
/ 02 мая 2018

Название не совсем понятно, но трудно описать проблему, с которой я столкнулся.

Давайте рассмотрим класс Signal с реализованным методом == и !=. (это упрощенная версия моей).

import numpy as np

class Signal:

    def __init__(self, fq, t0, tf):
        """
        Creation of the object.
        """
        # Amplitude and shape
        self.amp = float(8)

        # Timing and frequency
        self.t0 = t0
        self.tf = tf
        self.duration = round(self.tf - self.t0, 3)
        self.fq = fq                                 
        self.timeline = np.round(np.arange(t0, tf, 1/fq*1000), 3)

    def __eq__(self, s):
        """ == comparison method."""
        return self.fq == s.fq and self.t0 == s.t0 and self.tf == s.tf

    def __ne__(self, s):
        """ != comparison method."""
        return not self.__eq__(self, s)

Теперь давайте рассмотрим 2 списка объектов Signal:

t0 = 0
tf = 200
desired_n = [Signal(20, t0, tf), Signal(30, t0, tf), Signal(40, t0, tf)]
desired_n_minus_1 = [Signal(20, t0, tf), Signal(30, t0, tf)]

Чтобы найти, какой сигнал отсутствует в desired_n_minus_1, я просто зацикливаюсь и проверяю:

for s in desired_n:
    if s not in desired_n_minus_1:
         signal_missing = s
         break

Отлично, это работает! Однако ... в этом и заключается хитрость: у меня может быть один и тот же сигнал несколько раз в списке desired_n. Пример:

t0 = 0
tf = 200
desired_n = [Signal(20, t0, tf), Signal(30, t0, tf), Signal(30, t0, tf)]
desired_n_minus_1 = [Signal(20, t0, tf), Signal(30, t0, tf)]

В этом случае мое решение больше не работает, и мне нужна программа для возврата Signal(30, t0, tf). Мне все равно, какой из 2 он возвращает.

И это не так, тут худший случай:

t0 = 0
tf = 200
desired_n = [Signal(20, t0, tf), Signal(20, t0, tf), Signal(30, t0, tf), Signal(30, t0, tf)]
desired_n_minus_1 = [Signal(20, t0, tf), Signal(30, t0, tf), Signal(30, t0, tf)]

В этом случае мне нужно вернуть один из 2 Signal(20, t0, tf).

Обычно при работе с дубликатами я использую наборы, однако я не реализовывал (и никогда не делал ни разу в своей жизни) метод хеширования для объекта ...

Спасибо за помощь, чтобы найти выход из этой проблемы:)

Ответы [ 4 ]

0 голосов
/ 02 мая 2018

Дополнительное решение, которое я нашел:

for s in desired_n:
    if s not in desired_n_minus_1:
        signal_missing = s
        break
    elif desired_n.count(s) > desired_n_minus_1.count(s):
        signal_missing = s
        break
    else:
        continue
0 голосов
/ 02 мая 2018

Если вы можете быть уверены, что сигнал никогда не изменится после его создания, вы можете создать метод __hash__, хэшируя значения, которые вы сравниваете в __eq__:

 def __hash__(self):
    return hash((self.fq, self.t0, self.tf))

Тогда вы можете использовать наборы для удаления дубликатов.

0 голосов
/ 02 мая 2018

A set не будет работать в вашем случае, так как он не будет отслеживать множественность каждого элемента: во втором и третьем случаях у вас будет:

set(desired_n) == set(desired_n_minus_1)

Вместо этого вы можете включить desired_n_minus_1 и удалить эти элементы из desired_n:

output = list(desired_n)
for u in desired_n_minus_1:
    output.remove(u)
0 голосов
/ 02 мая 2018

Обычно вы можете просто реализовать __hash__, вызвав hash() для набора уникальных полей, например:

class Signal:
    ...
    def __hash__(self):
        return hash((self.fq, self.t0, self.tf))

А потом:

>>> a = Signal(10, 20, 30)
>>> b = Signal(20, 30, 40)
>>> c = Signal(10, 20, 30)  # same as a
>>> s = {a, b, c}
>>> len(s)
2
...