2009-09-29 16 views
36

Tengo un vector lógico, para el cual deseo insertar nuevos elementos en índices particulares. He encontrado una solución torpe a continuación, pero ¿hay una manera más ordenada?¿Cómo insertar elementos en un vector?

probes <- rep(TRUE, 15) 
ind <- c(5, 10) 
probes.2 <- logical(length(probes)+length(ind)) 
probes.ind <- ind + 1:length(ind) 
probes.original <- (1:length(probes.2))[-probes.ind] 
probes.2[probes.ind] <- FALSE 
probes.2[probes.original] <- probes 

print(probes) 

da

[1] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE 

y

print(probes.2) 

da

[1] TRUE TRUE TRUE TRUE TRUE FALSE TRUE TRUE TRUE TRUE TRUE FALSE 
[13] TRUE TRUE TRUE TRUE TRUE 

Así funciona, pero es feo mirar - alguna sugerencia?

+0

¿Por qué necesita hacer la inserción? – hadley

+0

larga historia, pero básicamente buscando ejecuciones de TRUE, pero tengo lugares predeterminados donde quiero dividir una carrera. La primera vez utilicé "rle" pero escalo muy mal, así que se me ocurrió esta solución de vector sucio –

Respuesta

29

Usted puede hacer algo de magia con índices:

En primer lugar crear vectores con valores de salida:

probs <- rep(TRUE, 15) 
ind <- c(5, 10) 
val <- c(probs, rep(FALSE,length(ind))) 
# > val 
# [1] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE 
# [13] TRUE TRUE TRUE FALSE FALSE 

Ahora truco. Cada elemento de edad recibe el rango, cada nuevo elemento recibe la mitad de rango

id <- c(seq_along(probs), ind+0.5) 
# > id 
# [1] 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 14.0 15.0 
# [16] 5.5 10.5 

A continuación, utilice order para ordenar en el orden correcto:

val[order(id)] 
# [1] TRUE TRUE TRUE TRUE TRUE FALSE TRUE TRUE TRUE TRUE TRUE FALSE 
# [13] TRUE TRUE TRUE TRUE TRUE 
+1

Agradable y furtivo: ¿qué tan bien se puede escalar con miles/millones de elementos? –

+0

En 1.58GHz Core2 system.time (orden (rnorm (1e6))) toma <2s – Marek

2

Eso es complicado. Aquí hay una manera. Se repite en la lista, insertando cada vez, por lo que no es demasiado eficiente.

probes <- rep(TRUE, 15) 
probes.ind <- ind + 0:(length(ind)-1) 
for (i in probes.ind) { 
    probes <- c(probes[1:i], FALSE, probes[(i+1):length(probes)]) 
} 

> probes 
[1] TRUE TRUE TRUE TRUE TRUE FALSE TRUE TRUE TRUE TRUE TRUE FALSE 
[13] TRUE TRUE TRUE TRUE TRUE 

Esto debería funcionar incluso si ind ha repetido elementos, aunque ind necesita ser ordenados para la construcción probes.ind para trabajar.

6

¿Qué tal esto:

> probes <- rep(TRUE, 15) 
> ind <- c(5, 10) 

> probes.ind <- rep(NA, length(probes)) 
> probes.ind[ind] <- FALSE 
> new.probes <- as.vector(rbind(probes, probes.ind)) 
> new.probes <- new.probes[!is.na(new.probes)] 
> new.probes 
[1] TRUE TRUE TRUE TRUE TRUE FALSE TRUE TRUE TRUE TRUE TRUE FALSE 
[13] TRUE TRUE TRUE TRUE TRUE 
+3

Sneaky! Utiliza el hecho de que como vector hace un colapso en columnas de la matriz creada por rbind. Esto se debe a que una matriz es solo un vector con información adicional que indica el número de filas y se almacena internamente en orden de columnas. Esto es parte de la definición del lenguaje R, pero puede ser un poco oscuro, dependiendo de quién esté leyendo el código ... – Harlan

+0

@Harlan Gran explicación. Eso hace una gran diferencia al trabajar con este ejemplo. – Rob

57

Estos son todos los enfoques muy creativos. Creo que trabajar con índices definitivamente es el camino a seguir (la solución de Marek es muy buena).

Me limitaré a mencionar que hay una función para hacer más o menos que: append().

probes <- rep(TRUE, 15) 
probes <- append(probes, FALSE, after=5) 
probes <- append(probes, FALSE, after=11) 

O usted podría hacer esto de forma recursiva con sus índices (que necesita para crecer el "después" de valor en cada iteración):

probes <- rep(TRUE, 15) 
ind <- c(5, 10) 
for(i in 0:(length(ind)-1)) 
    probes <- append(probes, FALSE, after=(ind[i+1]+i)) 

Por cierto, this question was also previously asked on R-Help. Como dice Barry:

"De hecho, diría que no hay forma de hacerlo, ya que no creo que puedas insertarlo en un vector, ¡tienes que crear un nuevo vector que produzca la ilusión de inserción!"

+0

No sabía acerca de la función de agregar, ¡gracias por llamar mi atención! Debería haber especificado en mi pregunta que no quería un bucle porque mis vectores reales tendrán miles/millones de elementos –

+1

Y uno puede establecer 'after = 0' para insertar un nuevo valor al comienzo de un vector. – coip

+0

Si 'ind' está ordenado, como parece suponer, puede hacer el ciclo más simplemente al revés:' for (i en length (ind): 1) append (..., after = ind [i]) ' ? –

7
probes <- rep(TRUE, 1000000) 
ind <- c(50:100) 
val <- rep(FALSE,length(ind)) 

new.probes <- vector(mode="logical",length(probes)+length(val)) 
new.probes[-ind] <- probes 
new.probes[ind] <- val 

Algunos tiempos: Mi sistema del usuario método transcurrido 0,03 0,00 0,03

Marek sistema del usuario método transcurrido 0,18 0,00 0.18

R anexar por el usuario del sistema de bucle transcurrido 1,61 0,48 2,10

+2

¡Una gran idea, parece ser la forma más eficiente de hacerlo! Sin embargo, debe desplazar todos los índices para que esto funcione según lo previsto, es decir, agregue 'ind <- ind + 0: (length (ind) -1)' antes de hacer asignaciones a 'new.probes'. – aoles

+0

Puede omitir el último paso (y la definición de 'val') simplemente inicializando' new.probes' con valores para reemplazar: 'new.probes <- rep (FALSE, length (probes) + length (val))'. Eso lo hace aún más rápido. –

1

O puede hacerlo utilizando la función insertRow del paquete miscTools.

probes <- rep(TRUE, 15) 
ind <- c(5,10) 
for (i in ind){ 
    probes <- as.vector(insertRow(as.matrix(probes), i, FALSE)) 
} 
+0

Llegué aquí buscando eso. Los trucos sobre el uso de los nombres para ordenar son geniales y profundizan mi comprensión del idioma, pero esto es mejor para mi situación. – Chris

Cuestiones relacionadas