Para muitos casos de uso, a resposta que você deseja é:
ys = set(y)
[item for item in x if item not in ys]
Este é um híbrido entre a resposta de aaronasterling e a resposta quântica .
A versão de aaronasterling faz len(y)
comparações de itens para cada elemento x
, portanto leva tempo quadrático. A versão do quantumSoup usa conjuntos, portanto, faz uma única pesquisa de conjunto em tempo constante para cada elemento em x
- mas, porque converte ambos x
e y
em conjuntos, perde a ordem dos seus elementos.
Ao converter apenas y
em um conjunto e iterar x
em ordem, você obtém o melhor dos dois mundos - tempo linear e preservação da ordem. *
No entanto, isso ainda tem um problema da versão do quantumSoup: requer que seus elementos sejam laváveis. Isso é bastante incorporado à natureza dos conjuntos. ** Se você está tentando, por exemplo, subtrair uma lista de dictos de outra lista de dictos, mas a lista a subtrair é grande, o que você faz?
Se você pode decorar seus valores de alguma maneira que eles sejam laváveis, isso resolve o problema. Por exemplo, com um dicionário simples cujos valores são eles mesmos hashable:
ys = {tuple(item.items()) for item in y}
[item for item in x if tuple(item.items()) not in ys]
Se seus tipos forem um pouco mais complicados (por exemplo, com frequência, você está lidando com valores compatíveis com JSON, que são hasháveis ou com listas ou dictos cujos valores são recursivamente do mesmo tipo), você ainda pode usar esta solução. Mas alguns tipos simplesmente não podem ser convertidos em nada que possa ser lavado.
Se seus itens não são, e não podem ser fabricados, laváveis, mas são comparáveis, você pode obter pelo menos tempo linear de log ( O(N*log M)
que é muito melhor que o O(N*M)
tempo da solução da lista, mas não tão bom quanto) o O(N+M)
horário da solução definida) classificando e usando bisect
:
ys = sorted(y)
def bisect_contains(seq, item):
index = bisect.bisect(seq, item)
return index < len(seq) and seq[index] == item
[item for item in x if bisect_contains(ys, item)]
Se seus itens não são laváveis nem comparáveis, você fica com a solução quadrática.
* Observe que você também pode fazer isso usando um par de OrderedSet
objetos, para os quais pode encontrar receitas e módulos de terceiros. Mas acho que isso é mais simples.
** O motivo pelo qual as pesquisas de conjunto são constantes é que tudo o que você precisa fazer é o valor do hash e verificar se há uma entrada para esse hash. Se não puder misturar o valor, isso não funcionará.