функция sub () заменяет все совпадения - PullRequest
0 голосов
/ 03 октября 2019

это снова я,

У меня проблема с функцией sub () в R: в документации написано: "sub и gsub выполняют замену первого и всех совпадений соответственно."

У меня есть код, в котором я хочу заменить только один элемент другим (условно, скажем, что если элемент появляется, я хочу, чтобы он был два раза в векторе - но это не обязательная информация).

Однако, если я выполняю подфункцию, она заменяет все. Вот некоторый код для демонстрации того, что происходит:

a = c("a", "b", "c", "d", "a", "b", "c", "d", "a", "a")
> sub("a", "f", a)
[1] "f" "b" "c" "d" "f" "b" "c" "d" "f" "f"
> gsub("a", "f", a)
[1] "f" "b" "c" "d" "f" "b" "c" "d" "f" "f"

Как вы можете видеть, в моем случае sub и gsub выполняют одно и то же действие, однако я хочу, чтобы результатом было следующее:

a = c("a", "b", "c", "d", "a", "b", "c", "d", "a", "a")
> sub("a", "f", a)
[1] "f" "b" "c" "d" "a" "b" "c" "d" "a" "a"

Я не понимаю, почему это происходит, мне это не соответствует документации. Кто-нибудь может объяснить мне причину или обходной путь?

Ответы [ 5 ]

3 голосов
/ 03 октября 2019

Вы можете использовать match для поиска первого попадания и использовать возвращенный индекс для замены строки.

a[match("a", a)]  <- "f"
a
# [1] "f" "b" "c" "d" "a" "b" "c" "d" "a" "a"
2 голосов
/ 03 октября 2019

Регулярное выражение в sub обрабатывает каждый вектор по-разному. Возможно, приведенный ниже пример поможет вам понять разницу в них.

a = c("aaaa", "b", "c", "d", "a", "b", "c", "d", "a", "a")
sub("a", "f", a)
#[1] "faaa" "b"    "c"    "d"    "f"    "b"    "c"    "d"    "f"    "f" 

gsub("a", "f", a)
#[1] "ffff" "b"    "c"    "d"    "f"    "b"    "c"    "d"    "f"    "f" 

, поэтому при sub только первый "a" превращается в "f", тогда как при gsub все "a" sповернуты к "f". Также это выглядит как точное совпадение, а не частичное совпадение, поэтому здесь нет необходимости использовать регулярные выражения.

Вы можете сравнить a с "a" и заменить первое вхождение на "f".

a = c("a", "b", "c", "d", "a", "b", "c", "d", "a", "a")
a[which.max(a == "a")] <- "f"
a
#[1] "f" "b" "c" "d" "a" "b" "c" "d" "a" "a"
1 голос
/ 03 октября 2019

Предполагая только один символ на элемент, и если вы можете позволить себе объединять и разделять векторы, вы можете сделать

> unlist(strsplit(sub("a","f",paste0(a,collapse="")),""))
 [1] "f" "b" "c" "d" "a" "b" "c" "d" "a" "a"
0 голосов
/ 03 октября 2019

Как @ user2974951 указывает в своем комментарии, sub(pat, repl, x) векторизовано, что означает, что он заменит первый экземпляр pat на repl в каждый элемент x.

Если вы должны использовать sub, вы можете объединить записи, заменить pat на repl, а затем снова разбить строку на каждый символ.

unlist(strsplit(sub("a", "f", paste0(a, collapse = "")), ""))
#[1] "f" "b" "c" "d" "a" "b" "c" "d" "a" "a"
0 голосов
/ 03 октября 2019

Вы можете использовать grepl здесь, чтобы найти все индексы во входном векторе, которые содержат "a". Затем выборочно замените только первый соответствующий индекс.

a <- c("a", "b", "c", "d", "a", "b", "c", "d", "a", "a")
a[min(which(grepl("a", a) == TRUE))] <- "f"
a

[1] "f" "b" "c" "d" "a" "b" "c" "d" "a" "a"

Обратите внимание, что sub() будет фактически первым соответствием в шаблоне, но для каждого входа . Функция sub() векторизована, и когда вы передаете ей вектор вместо единственного значения, он заменяет первое совпадение в каждом значении вектора, а не только в первом элементе.

...