Eu quero fazer algo semelhante a isto:
>>> x = [1,2,3,4,5,6,7,8,9,0]
>>> x
[1, 2, 3, 4, 5, 6, 7, 8, 9, 0]
>>> y = [1,3,5,7,9]
>>> y
[1, 3, 5, 7, 9]
>>> y - x # (should return [2,4,6,8,0])
Mas isso não é suportado pelas listas python. Qual é a melhor maneira de fazer isso?
Respostas:
Use uma compreensão da lista:
Se você deseja usar a
-
sintaxe do infix, basta:você pode usá-lo como:
Mas se você não precisar absolutamente de propriedades da lista (por exemplo, fazer pedido), use conjuntos como as outras respostas recomendam.
fonte
list
para nomes de variáveis, pois sombreia olist
construtor. Se você usa 'list', preceda-o com um sublinhado. Além disso, ao deixar cair o*
, você quebrou meu código ...[1,1,2,2] - [1,2]
, receberá uma lista vazia.[1,1,2,2] - [2]
dá[1,1]
Portanto, não é realmente lista subtração, é mais como "Lista de Lista X , sem elementos de conjunto Y " .y
em umset
antes de cada verificação (que é um custo semelhante ao trabalho original). Você precisaria fazeryset = set(y)
fora do listcomp, depois testarif item not in yset
ou como um hack flagrante, o[item for yset in [set(y)] for item in x if item not in yset]
que abusa dos listcomps aninhados para armazenar em cache oyset
one-liner. Uma solução de uma linha um pouco menos feia e com desempenho adequado seria usarlist(itertools.filterfalse(set(y).__contains__, x))
porque o argumento parafilterfalse
é construído apenas uma vez.Usar diferença definida
Ou você pode apenas ter conjuntos xey para não precisar fazer conversões.
fonte
TypeError: unhashable type: 'dict'
Essa é uma operação de "subtração de conjunto". Use a estrutura de dados definida para isso.
No Python 2.7:
Resultado:
fonte
se itens duplicados e pedidos forem problema:
[i for i in a if not i in b or b.remove(i)]
fonte
O(m * n)
tempo de execução (e eu me encolho sempre que um listcomp inclui efeitos colaterais); você pode aprimorá-lo usandocollections.Counter
para obter oO(m + n)
tempo de execução.Para muitos casos de uso, a resposta que você deseja é:
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 elementox
, 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 emx
- mas, porque converte ambosx
ey
em conjuntos, perde a ordem dos seus elementos.Ao converter apenas
y
em um conjunto e iterarx
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:
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 oO(N*M)
tempo da solução da lista, mas não tão bom quanto) oO(N+M)
horário da solução definida) classificando e usandobisect
: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á.
fonte
A pesquisa de valores em conjuntos é mais rápida do que a pesquisa em listas:
Acredito que isso será dimensionado um pouco melhor do que:
Ambos preservam a ordem das listas.
fonte
set(y)
e não será convertidoy
em um novo conjunto em cada loop? Caso contrário, você resposta necessidade de abarnert:ys = set(y); [i for i in x if i not in ys]
.if i not in set(y)
leva 25% mais tempo do queif i not in y
(ondey
está uma lista). A pré-conversão do conjunto leva 55% menos tempo. Testado com bastante curtox
ey
, mas as diferenças devem ser mais pronunciadas com o comprimento, se houver.y
para cada elemento dex
; a menos que a comparação de igualdade seja realmente cara em relação ao cálculo de hash, isso sempre será perdidoitem not in y
.Se as listas permitirem elementos duplicados, você poderá usar o Contador de coleções:
Se você precisar preservar a ordem dos elementos de x:
fonte
Counter.subtract
não remove elementos com valor zero (-
e remove-=
, mas nãosubtract
); portanto, você nunca para de remover elementos. Você deseja substituirnot v in c
pornot c[v]
(que retorna zero para elementos inexistentes, para que você possa testar com segurança o retorno para "zerar" vianot
).Eu acho que a maneira mais fácil de conseguir isso é usando set ().
fonte
As outras soluções têm um de alguns problemas:
x = [1, 2, 2, 2]
ey = [2, 2]
convertemy
em aset
, e removem todos os elementos correspondentes (deixando[1]
apenas) ou removem um de cada elemento exclusivo (deixando[1, 2, 2]
), quando o comportamento adequado seria remover2
duas vezes, saindo[1, 2]
ouO(m * n)
funcionam, onde uma solução ideal podeO(m + n)
funcionarAlain estava no caminho certo
Counter
para resolver os nºs 2 e 3, mas essa solução perderá a ordem. A solução que preserva a ordem (removendo as primeirasn
cópias de cada valor paran
repetições noslist
valores a serem removidos) é:Experimente online!
Para remover as últimas cópias de cada elemento, basta alterar o
for
loop parafor val in reversed(x):
e adicionarout.reverse()
imediatamente após sair dofor
loop.Construir o
Counter
isO(n)
em termos dey
comprimento, iterarx
éO(n)
em termos dex
comprimento, eCounter
os testes e mutações de membros sãoO(1)
, enquantolist.append
são amortizadosO(1)
(um dadoappend
pode serO(n)
, mas para muitosappend
s, a média geral do grande O,O(1)
pois cada vez menos deles exigem uma realocação); portanto, o trabalho geral realizado éO(m + n)
.Você também pode testar para determinar se havia algum elemento
y
que não foi removidox
pelo teste:fonte
int
s em matriz de comprimento fixo) ou tem de fazer mais doO(m + n)
trabalho (por exemplo, a próxima melhor grande -O seria criar uma classificaçãolist
de pares únicos de valor / contagem, transformandoO(1)
dict
pesquisas em pesquisasO(log n)
binárias; você precisaria de valores únicos com suas contagens, não apenas valores não únicos classificados, porque, caso contrário, estaria pagandoO(n)
custos para remover o elementos da classificaçãolist
).Tente isso.
fonte
A resposta fornecida por @aaronasterling parece boa, no entanto, não é compatível com a interface padrão da lista:
x = MyList(1, 2, 3, 4)
vsx = MyList([1, 2, 3, 4])
. Assim, o código abaixo pode ser usado como um mais amigável à lista de python:Exemplo:
fonte
Eu acho que isso é mais rápido:
fonte
Este exemplo subtrai duas listas:
fonte