Parece que el OP solo estaba preocupado por el caso de dos variables, pero dado que StackOverflow también es para aquellos que buscan la misma pregunta más adelante, intentaré abordar el caso genérico aquí con cierto detalle; Una respuesta anterior ya contiene una respuesta genérica usando itertools.permutations()
, pero ese método lleva a O(N*N!)
comparaciones, ya que hay N!
permutaciones con N
elementos cada una. (Esta fue la principal motivación para esta respuesta)
Primero, resumamos cómo algunos de los métodos en respuestas anteriores se aplican al caso genérico, como motivación para el método presentado aquí. Usaré A
para referirme (x, y)
y B
para referirme (a, b)
, que pueden ser tuplas de longitud arbitraria (pero igual).
set(A) == set(B)
es rápido, pero solo funciona si los valores son hashables y puede garantizar que una de las tuplas no contenga ningún valor duplicado. (Por ejemplo {1, 1, 2} == {1, 2, 2}
, como señaló @ user2357112 bajo la respuesta de @Daniel Mesejo)
El método anterior se puede ampliar para trabajar con valores duplicados mediante el uso de diccionarios con recuentos, en lugar de conjuntos: (Esto todavía tiene la limitación de que todos los valores deben ser hashables, por ejemplo, los valores mutables como list
no funcionarán)
def counts(items):
d = {}
for item in items:
d[item] = d.get(item, 0) + 1
return d
counts(A) == counts(B)
sorted(A) == sorted(B)
no requiere valores hashables, pero es un poco más lento y requiere valores ordenables en su lugar. (Entonces, por ejemplo complex
, no funcionará)
A in itertools.permutations(B)
no requiere valores hashables u ordenables, pero como ya se mencionó, tiene O(N*N!)
complejidad, por lo que incluso con solo 11 elementos, puede llevar más de un segundo terminar.
Entonces, ¿hay alguna manera de ser tan general, pero hacerlo considerablemente más rápido? Por qué sí, al verificar "manualmente" que hay la misma cantidad de cada elemento: (La complejidad de este es O(N^2)
, por lo que tampoco es bueno para entradas grandes; en mi máquina, 10k elementos pueden tomar más de un segundo, pero con entradas más pequeñas, como 10 elementos, esto es tan rápido como los otros)
def unordered_eq(A, B):
for a in A:
if A.count(a) != B.count(a):
return False
return True
Para obtener el mejor rendimiento, es posible que primero desee probar el dict
método basado, recurrir al sorted
método basado si eso falla debido a valores no compartibles y, finalmente, recurrir al count
método basado si eso también falla debido a valores no ordenados.
x,y, a,b
sean: ¿son ints / floats / strings, objetos arbitrarios o qué? Si fueran incorporada tipos y fue posible mantener tantox,y
ya,b
en forma ordenada, entonces usted podría evitar la segunda rama. Tenga en cuenta que la creación de un conjunto hará que cada uno de los cuatro elementosx,y, a,b
se mezcle, lo que podría o no ser trivial o tener una implicación de rendimiento dependiendo completamente de qué tipo de objetos sean.