Aquí tengo los números enteros 1:7
de cuatro particiones diferentes, es decir, {1}, {2,3,4}, {5,6} y {7} y esas particiones están inscritos en una lista, es decir, list(1,c(2,3,4),c(5,6),7)
. Trato las particiones como conjuntos, de modo que la permutación diferente de elementos dentro de una partición se reconozca como la misma. Por ejemplo, list(1,c(2,3,4),c(5,6),7)
y list(7,1,c(2,3,4),c(6,5))
son equivalentes.
Tenga en cuenta que no hay repetición de elementos en la lista, por ejemplo, no list(c(1,2),c(2,1),c(1,2))
, ya que este problema está discutiendo particiones exclusivas en todo el conjunto.
Enumeré algunas de las diferentes permutaciones en la lista a lst
continuación
lst <- list(list(1,c(2,3,4),c(5,6),7),
list(c(2,3,4),1,7,c(5,6)),
list(1,c(2,3,4),7,c(6,5)),
list(7,1,c(3,2,4),c(5,6)))
y lo que quiero hacer es verificar que todas las permutaciones sean equivalentes. En caso afirmativo, obtenemos el resultado TRUE
.
Lo que hice hasta ahora es para ordenar los elementos dentro de cada partición, y se utiliza setdiff()
con interset()
y union()
para juzgarlo (ver mi código de abajo)
s <- Map(function(v) Map(sort,v),lst)
equivalent <- length(setdiff(Reduce(union,s),Reduce(intersect,s),))==0
Sin embargo, supongo que este método sería lento siempre que el tamaño de la partición aumente. ¿Hay algún enfoque más rápido para hacerlo? Apreciado de antemano!
- algunos casos de prueba (datos de tamaño pequeño)
# should return `TRUE`
lst1 <- list(list(1,c(2,3,4),c(5,6)),
list(c(2,3,4),1,c(5,6)),
list(1,c(2,3,4),c(6,5)))
# should return `TRUE`
lst2 <- list(list(1:2, 3:4), list(3:4, 1:2))
# should return `FALSE`
lst3 <- list(list(1,c(2,3,4),c(5,6)), list(c(2,3,4),1,c(5,6)), list(1,c(2,3,5),c(6,4)))
fuente
Map
llamadas múltipleslst_equal = list(list(1:2, 3:4), list(3:4, 1:2))
y también uno donde el resultado debería serFALSE
, tal vezlst_false <- list(list(1,c(2,3,4),c(5,6)), list(c(2,3,4),1,c(5,6)), list(1,c(2,3,5),c(6,4)))
FALSE
. De esa manera, cuando una respuesta funciona en algunos casos de prueba, pero no en todos, es fácil diagnosticar por qué. Cuando solo hay un solo ejemplo, pierdes matices en los resultados de la prueba. También es bueno agregar nuevos ejemplos en lugar de cambiar los ejemplos existentes en personas que ya han trabajado en ellos.lst
es potencialmente larga, podría ganar eficiencia con otros enfoques. Por ejemplo, una primera verificación quelength(unique(lengths(lst))) == 1
regresaría muy rápidamenteFALSE
si alguna de las listas internas tiene el número incorrecto de elementos ...lst
, al compararlst[[i]]
alst[[1]]
, y de esa manera se puede parar tan pronto como se encuentra una falta de coincidencia, en lugar de hacer todas las comparaciones. Silst
es largo yFALSE
s son comunes, esto podría ser una gran ganancia de eficiencia, pero probablemente no valga la pena de otra manera.Respuestas:
Una publicación sobre
R
y cualquier variante de rápido no está completa sin una solución con rcpp .Para maximizar la eficiencia, elegir la estructura de datos correcta será de suma importancia. Nuestra estructura de datos necesita almacenar valores únicos y también tener inserción / acceso rápido. Esto es exactamente lo que encarna std :: unordered_set . Solo necesitamos determinar cómo podemos identificar de forma única cada uno
vector
de los desordenadosintegers
.Introduzca el teorema fundamental de la aritmética
El TLC establece que cada número puede ser representado de manera única (hasta el orden de los factores) por el producto de números primos.
Aquí hay un ejemplo que demuestra cómo podemos usar el TLC para descifrar rápidamente si dos vectores son equivalentes hasta el orden (NB a
P
continuación es una lista de números primos ...(2, 3, 5, 7, 11, etc.)
:A partir de esto, vemos eso
vec1
yvec3
correlacionamos correctamente con el mismo número, mientras quevec2
se asigna a un valor diferente.Dado que nuestros vectores reales pueden contener hasta cien enteros menores que 1000, la aplicación del TLC producirá números extremadamente grandes. Podemos evitar esto aprovechando la regla del producto del logaritmo:
Con esto a nuestra disposición, podremos abordar ejemplos de números mucho más grandes (Esto comienza a deteriorarse en ejemplos extremadamente grandes).
Primero, necesitamos un generador de números primos simple (NB En realidad estamos generando el registro de cada número primo).
Y aquí está la implementación principal:
Aquí están los resultados cuando los aplica
lst1, lst2, lst3, & lst (the large one)
@GKi.Y aquí hay algunos puntos de referencia con el
units
parámetro establecido enrelative
.Aproximadamente 3 veces más rápido que la solución más rápida hasta ahora en el ejemplo más grande.
Para mí, este resultado dice mucho de la belleza y la eficiencia de lo
base R
que muestran @GKi, @ chinsoon12, @Gregor, @ThomasIsCoding y más. Escribimos alrededor de 100 líneas muy específicasC++
para obtener una velocidad moderada. Para ser justos, lasbase R
soluciones terminan llamando principalmente código compilado y terminan utilizando tablas hash como lo hicimos anteriormente.fuente
Después de ordenar puedes usar
duplicated
yall
.Alternativa: ordenar en un bucle
Alternativa: ordenar durante el ciclo y permitir la salida anticipada
o usando
setequal
o mejorando ligeramente la idea de @ chinsoon12 para intercambiar la lista con un vector!
o evitar el segundo
order
o intercambiar
order
conmatch
(ofmatch
)O sin salida anticipada.
o escrito en C ++
¡Gracias a @Gregor por sugerencias para mejorar la respuesta!
fuente
lst <- list(list(1,c(2,3,4),c(5,6),7), list(c(2,3,4),1,7,c(5,6)), list(1,c(2,3,4),7,c(6,5)), list(7,1,c(3,2,4),c(5,6)))
será juzgado comoFALSE
min
!Actuación:
Bibliotecas:
Funciones:
Datos:
fuente
length(setdiff(Reduce(union,s),Reduce(intersect,s)))==0
, lo siento por mi error ....Esperemos que la segunda vez tenga suerte
Casos de prueba:
controles:
código de tiempo:
tiempos:
fuente