1
votes

Comment puis-je trouver et remplacer une séquence spécifique de nombres dans un vecteur de R?

Je dois remplacer la séquence "1,0,1" par "1,1,1" chaque fois qu'elle se trouve dans un vecteur. Comment puis-je faire cela?

x <- c (1,2,3,4,1,1,1,1,1,2)

Modifier: Cette recherche doit être dynamique. Si après le passage de 1,0,1 à 1,1,1 un autre 1,0,1 se produit, il doit également être remplacé.

Considérant:

x <- c (1,2,3,4,1,1,1,0,1,2)

Je veux que l'algorithme fasse:

x <- c (1,2,3,4,1,0,1,0,1,2)

Et après:

x <- c(1,2,3,4,1,0,1)


3 commentaires

Désordonné, mais vous pouvez faire quelque chose comme scan (text = gsub ("1, 0, 1", "1, 1, 1", toString (x)), sep = ",") .


et si vous avez x <- c (1,2,3,4,1,0,1,0,1) ??


@Onyambu Dans ce cas, l'algorithme doit faire: x <- (1,2,3,4,1,0,1,0,1) x <- (1,2 , 3,4,1,1,1,0,1) Après cela, il devrait détecter à nouveau la séquence 1.0.1 x <- (1,2,3,4,1,1, 1,1,1)


3 Réponses :


3
votes

Une fonction qui traite dynamiquement la longueur du sous-vecteur (recherché). Les solutions qui convertissent vers / à partir de chaînes seront extrêmement inefficaces de manière asymptotique. Les solutions qui codent en dur un sous-vec de longueur 3 sont limitées aux sous-vec de longueur 3. Cela concerne n'importe quoi tant que le vecteur source est aussi grand ou plus grand que le sous-vec à trouver.

z <- c(1,1,1)
x <- c(1,2,3,4,1,0,1)
y <- c(1,0,1)
z <- c(1,1,1)
ind <- find_subvec(x, y)
for (i in ind) x[i + seq_along(y) - 1] <- z
x
# [1] 1 2 3 4 1 1 1

Use:

find_subvec(c(1,2,3,4,1,0,1), c(1,0,1))
# [1] 5
find_subvec(c(1,2,3,4,1,0,1,0,1), c(1,0,1))
# [1] 5 7

Un remplacement littéral.

#' Find a matching sub-vector
#'
#' Given a vector (`invec`) and a no-larger sub-vector (`subvec`),
#' determine if the latter occurs perfectly.
#' @param invec vector
#' @param subvec vector
#' @return integer positions, length 0 or more
find_subvec <- function(invec, subvec) {
  sublen <- seq_along(subvec) - 1L
  if (length(subvec) > length(invec)) return(integer(0))
  which(
    sapply(seq_len(length(invec) - length(subvec) + 1L),
           function(i) all(subvec == invec[i + sublen]))
  )
}


5 commentaires

Remarque: pour le find_subvec , vous pouvez consulter Obtenez les index d'un vecteur de nombres dans un autre vecteur pour des alternatives sur ce thème. Acclamations


L'approche que j'avais envisagée est suffisamment similaire à la vôtre que je ne pense pas qu'elle vaille la peine d'être publiée comme une réponse distincte. Les principales différences sont d'abord de vérifier si nous devons faire quelque chose, et deuxièmement, d'utiliser une boucle plus simple plutôt que sapply , ce qui peut être un peu cher. Notez que les résultats ne sont pas identiques aux vôtres (voir le commentaire à l'essentiel).


L'une des principales différences que vous mettez en évidence est l'hypothèse de "conditions avant tout changement" par rapport à "vérifier la condition après chaque changement" . Ce dernier est peut-être un peu plus de travail. Je ne pense pas que l'un ou l'autre soit nettement meilleur, car cela dépend entièrement de l'intention du PO. Quant à sapply être plus rapide ... confirmé et intéressant! Pendant des années, il y a eu une telle présomption opposée !


Le passage à vapply réduit considérablement la marge de performance, mais elle est encore plus élevée. ( grattage de tête ...)


vapply devrait généralement être plus rapide que sapply ne serait-ce que parce que sapply cherche à savoir si les résultats peuvent être simplifiés, alors qu'avec vapply vous fournissez le modèle souhaité. Il est convenu que sans la contribution du PO sur la vérification des conditions avant ou après le changement, nous sommes en quelque sorte en train de poignarder dans le noir ici.



-1
votes

Cela devrait fonctionner assez bien

library(tidyverse)

x <- c(1,2,3,4,1,0,1,0,1)

x %>% 
  reduce(str_c) %>% 
  str_replace_all("(?<=1)0(?=1)","1")
#> [1] "123411111"

Créé le 14/06/2020 par paquet reprex (v0.3.0)


0 commentaires

1
votes

Il peut y avoir des cas extrêmes comme mentionné par @Onyambu lorsque les résultats attendus ne sont pas clairs, mais une option pourrait être:

x + (x == 0 & c(NA, head(x, -1)) == 1 & c(tail(x, -1), NA) == 1)

1] 1 2 3 4 1 1 1

Ici, il ne traite pas x comme une chaîne, mais il évalue si les valeurs de décalage et d'avance sont 1 et la valeur du milieu est 0.


0 commentaires