daroczig escribe "se podría escribir un código mucho más limpio basado en diff
" ...
Aquí hay una manera:
split(v, cumsum(diff(c(-Inf, v)) != 1))
EDITAR (tiempos añadidos):
Tommy descubierto que esto podría sea más rápido teniendo cuidado con los tipos; La razón por la que se hizo más rápido es que split
es más rápido en enteros, y en realidad es aún más rápido en factores.
Aquí está la solución de Joshua; el resultado del cumsum
es numérico porque está siendo c
'd con 1
, por lo que es el más lento.
system.time({
a <- cumsum(c(1, diff(v) != 1))
split(v, a)
})
# user system elapsed
# 1.839 0.004 1.848
Sólo c
ing con 1L
lo que el resultado es un número entero que lo acelera considerablemente.
system.time({
a <- cumsum(c(1L, diff(v) != 1))
split(v, a)
})
# user system elapsed
# 0.744 0.000 0.746
Esta es la solución de Tommy, para referencia; también se divide en un número entero.
> system.time({
a <- cumsum(c(TRUE, diff(v) != 1L))
split(v, a)
})
# user system elapsed
# 0.742 0.000 0.746
Aquí está mi solución original; también se está dividiendo en un número entero.
system.time({
a <- cumsum(diff(c(-Inf, v)) != 1)
split(v, a)
})
# user system elapsed
# 0.750 0.000 0.754
Aquí es Joshua, con el resultado de convertir en un entero antes de la split
.
system.time({
a <- cumsum(c(1, diff(v) != 1))
a <- as.integer(a)
split(v, a)
})
# user system elapsed
# 0.736 0.002 0.740
Todas las versiones que split
en un vector de número entero son sobre el mismo; podría ser aún más rápido si ese vector entero ya fuera un factor, ya que la conversión de un número entero a un factor en realidad lleva aproximadamente la mitad del tiempo. Aquí lo transformo en un factor directamente; esto no se recomienda en general porque depende de la estructura de la clase de factor. Esto se hace aquí solo con fines de comparación.
system.time({
a <- cumsum(c(1L, diff(v) != 1))
a <- structure(a, class = "factor", levels = 1L:a[length(a)])
split(v,a)
})
# user system elapsed
# 0.356 0.000 0.357
sí, esta es una manera mucho más ordenada! :) No sabía sobre 'split', gracias por dirigir mi atención a esta útil función. – daroczig
Debo señalar que se debe tener cuidado cuando se usa 'as.integer' ya que devuelve el valor truncado, que puede no ser el que se desea cuando el numérico se creó con aritmética de punto flotante, por ejemplo,' as.integer (0.3 * 3 + 0.1) 'devuelve' 0'. – Aaron