Je veux créer une séquence entre deux lettres, disons "b"
et "f"
. Donc, la sortie est
"b" "c" "d" "e" "f"
Pour les chiffres, on peut faire
2:6 #which gives output as
[1] 2 3 4 5 6
Y at-il un moyen facile de faire cela avec des lettres aussi?
J'ai traversé Génère une séquence de caractères de 'A' - 'Z' mais cela produit toutes les lettres et non une séquence entre des lettres spécifiques.
Ma solution actuelle est,
indx <- which(letters %in% c("b", "f"));
letters[indx[1] : indx[2]]
#[1] "b" "c" "d" "e" "f"
Cela fonctionne, mais je suis curieux de savoir s’il existe un moyen facile de faire cela ou d’effectuer une fonction dans l’un des paquets que j’ai manqués.
Remarque: Je ne veux pas letters[2:6]
comme je ne sais pas 2 et 6 à l’avance. Cela pourrait être entre deux lettres.
Ce serait une autre option de base R:
letters[(letters >= "b") & (letters <= "f")]
# [1] "b" "c" "d" "e" "f"
Vous pouvez créer votre propre fonction:
`%:%` <- function(l, r) {
intToUtf8(seq(utf8ToInt(l), utf8ToInt(r)), multiple = TRUE)
}
Usage:
"b" %:% "f"
# [1] "b" "c" "d" "e" "f"
"f" %:% "b"
# [1] "f" "e" "d" "c" "b"
"A" %:% "D"
# [1] "A" "B" "C" "D"
Une autre option avec match
, seq
et do.call
:
letters[do.call(seq, as.list(match(c("b","f"), letters)))]
qui donne:
[1] "b" "c" "d" "e" "f"
Faire en sorte que cela fonctionne avec les lettres minuscules et majuscules:
char_seq <- function(lets) {
switch(all(grepl("[[:upper:]]", lets)) + 1L,
letters[do.call(seq, as.list(match(lets, letters)))],
LETTERS[do.call(seq, as.list(match(lets, LETTERS)))])
}
la sortie de ceci:
> char_seq(c("b","f")) [1] "b" "c" "d" "e" "f" > char_seq(c("B","F")) [1] "B" "C" "D" "E" "F"
Cette fonction peut être étendue avec des contrôles sur l'exactitude de l'entrée:
char_seq <- function(lets) {
g <- grepl("[[:upper:]]", lets)
if(length(g) != 2) stop("Input is not of length 2")
if(sum(g) == 1) stop("Input does not have all lower-case or all upper-case letters")
switch(all(g) + 1L,
letters[do.call(seq, as.list(match(lets, letters)))],
LETTERS[do.call(seq, as.list(match(lets, LETTERS)))])
}
donnant lieu à des messages d'erreur corrects lorsque l'entrée n'est pas correcte:
> char_seq(c("B")) Error in char_seq(c("B")) : Input is not of length 2 > char_seq(c("b","F")) Error in char_seq(c("b", "F")) : Input does not have all lower-case or all upper-case letters
Jouer avec UTF, quelque chose comme:
intToUtf8(utf8ToInt("b"):utf8ToInt("f"), multiple = TRUE)
# [1] "b" "c" "d" "e" "f"
Pourquoi pas?
letters[which(letters == 'b') : which(letters == 'f')]
Peut-être que l’utilisation des versions brutes des lettres, puis la conversion en caractères, pourraient être utilisées pour définir une fonction infixe analogue à ":"
`%c:%` <- function(x,y) { strsplit( rawToChar(as.raw(
seq(as.numeric(charToRaw(x)), as.numeric(charToRaw(y))))), "" )[[1]]}
> 'a' %c:% 'g'
[1] "a" "b" "c" "d" "e" "f" "g"
Je ne prétends certainement pas que cela répond à la demande de "moyen facile de faire cela" et je ne suis même pas sûr que ce serait plus efficace, mais cela introduit quelques fonctions potentiellement utiles.
Je sais que c'est mal vu, mais voici une solution eval(parse(...))
LETTERS[eval(parse(text = paste(which(LETTERS %in% c('B', 'F')), collapse = ':')))]
#[1] "B" "C" "D" "E" "F"
Tout d'abord: votre code
which(letters %in% c("b", "f"))
Est-ce une écriture valide mais compliquée
match(c('b', 'f'), letters)
(Pourquoi “alambiqué”? Parce que %in%
est un wrapper autour de match
pour un cas d’utilisation spécifique, qui transforme explicitement l’index numérique en une valeur logique, c’est-à-dire l’opération inverse de which
.)
Ensuite, vous pouvez bien sûr utiliser le résultat et le convertir en une plage via idx[1L] : idx[2L]
et il n’ya rien de mal à cela dans ce cas. Mais R a une manière idiomatique d’exprimer le concept d’appel d’une fonction utilisant un vecteur comme paramètre: do.call
:
do.call(`:`, as.list(match(c('b', 'f'), letters)))
Ou équivalent:
do.call(seq, as.list(match(c('b', 'f'), letters)))
{purrr} nous permet de faire la même chose sans le as.list
:
purrr::invoke(seq, match(c('b', 'f'), letters))
Et enfin, nous avons un sous-ensemble:
letters[purrr::invoke(seq, match(c('b', 'f'), letters))]