2009-09-29 7 views
36

J'ai un vecteur logique, pour lequel je souhaite insérer de nouveaux éléments à des index particuliers. Je suis venu avec une solution maladroite ci-dessous, mais y a-t-il une façon plus simple?Comment insérer des éléments dans un vecteur?

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) 

donne

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

et

print(probes.2) 

donne

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

Il fonctionne, mais est laide à la recherche - des suggestions?

+0

Pourquoi avez-vous besoin de faire l'insertion? – hadley

+0

longue histoire, mais essentiellement à la recherche de courses de TRUE, mais ont des endroits prédéterminés où je veux rompre une course. La première fois que j'ai utilisé "rle", mais il a très peu évolué, donc est venu avec cette solution de vecteur sale –

Répondre

29

Vous pouvez faire de la magie avec des index:

d'abord créer vecteur avec des valeurs de sortie:

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 

maintenant affaire. Chaque ancien élément se classe, chaque nouvel élément reçoit la moitié de rang

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 

Utilisez ensuite order pour trier dans le bon ordre:

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

Agréable et sournois - dans quelle mesure l'échelle de l'ordre est-elle à l'échelle de milliers/millions d'éléments? –

+0

Sur 1.58GHz Core2 system.time (order (rnorm (1e6))) prend <2s – Marek

2

C'est sorta délicat. Voici un moyen. Il itère sur la liste, en insérant chaque fois, donc ce n'est pas trop efficace.

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 

Cela devrait même fonctionner si ind a des éléments répétés, mais ind n'a pas besoin d'être triés pour la construction de probes.ind travailler.

6

Que diriez-vous ceci:

> 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! Utilise le fait que as.vector effectue un effondrement en colonne de la matrice créée par rbind. C'est parce qu'une matrice est juste un vecteur avec des informations supplémentaires qui indique le nombre de lignes, et est stocké en interne dans l'ordre des colonnes. Cela fait partie de la définition du langage R, mais peut-être un peu obscur, en fonction de qui lit le code ... – Harlan

+0

@Harlan Grande explication. Cela fait une grande différence en travaillant à travers cet exemple. – Rob

57

Ce sont des approches très créatives. Je pense que travailler avec des index est certainement la voie à suivre (la solution de Marek est très agréable).

Je voudrais juste mentionner qu'il ya une fonction pour faire à peu près que: append().

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

Ou vous pouvez le faire récursive avec vos index (vous devez développer la « après » la valeur à chaque itération):

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

Soit dit en passant, this question was also previously asked on R-Help. Comme le dit Barry:

"En fait, je dirais qu'il n'y avait aucune façon de faire cela, car je ne pense pas que vous pouvez réellement insérer dans un vecteur - vous devez créer un nouveau vecteur qui produit l'illusion d'insertion!"

+0

Je ne connaissais pas la fonction d'ajout, merci de m'avoir porté à mon attention! J'aurais dû spécifier dans ma question que je ne voulais pas de boucle car mes vrais vecteurs auront des milliers/millions d'éléments –

+1

Et on peut définir 'after = 0' pour insérer une nouvelle valeur au début d'un vecteur. – coip

+0

Si 'ind' est trié, comme vous semblez le supposer, pouvez-vous faire la boucle plus simplement à l'envers:' for (i en longueur (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 

Quelques timings: Ma méthode système utilisateur écoulèrent 0,03 0,00 0,03

Marek méthode système utilisateur écoula 0,18 0,00 0.18

R append avec boucle système utilisateur écoula 1,61 0,48 2,10

+2

Bonne idée, semble être le moyen le plus efficace de le faire! Cependant, vous devez décaler tous les index pour que cela fonctionne comme prévu, c'est-à-dire ajouter 'ind <- ind + 0: (length (ind) -1)' avant de faire des affectations à 'new.probes'. – aoles

+0

Vous pouvez omettre la dernière étape (et la définition de 'val') en initialisant simplement' new.probes' avec des valeurs à remplacer: 'new.probes <- rep (FALSE, longueur (sondes) + longueur (val))'. Cela le rend encore plus rapide. –

1

Ou vous pouvez le faire en utilisant la fonction insertRow du paquet miscTools.

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

Je suis arrivé ici à la recherche de cela. Les astuces sur l'utilisation des noms pour trier sont cool et approfondir ma compréhension de la langue, mais c'est mieux pour ma situation. – Chris

Questions connexes