#r #regex #list #pattern-matching
#r #регулярное выражение #Список #сопоставление с шаблоном
Вопрос:
У меня есть вектор адресов (небольшой фрагмент показан ниже)
df=c("westmoorings east","chaguanas proper","bloody bay" ,"westmooorings",
"el doraldo","rousillac34") (full length=5432)
и еще один вектор ссылочных городов / областей (см. фрагмент ниже)
areas=c("arima","port of spain","chaguanas") (full length=20)
что я хотел бы сделать, так это сгруппировать адреса в df
по областям в areas
векторе, например, адрес chaguanas proper
будет сгруппирован под chaguanas
. Я использую список для хранения результатов. Код, который я использую для достижения этой цели, является :
L=list()
for(i in 1:length(areas)){
ind=grep(paste(areas[i]),df)
L[i]=df[ind]
df[-ind] #updates the df to exclude all addresses already stored in L[i]
}
Проблема заключается в строке L[i]=df[ind]
. Я получаю сообщение об ошибке « number of items to replace is not a multiple of replacement length
» Кто-нибудь может помочь с этим? Я добиваюсь соответствия шаблону для работы, но сохранение результатов в компонентах списка вызывает эту ошибку. Кстати, я использую R.
Комментарии:
1. Если совпадения нет, grep возвращает NULL или
numeric(0)
. Я думаю, вам нуженif/else
.
Ответ №1:
Я бы предложил это после некоторых незначительных изменений в вашем коде:
#Data
df=c("westmoorings east","chaguanas proper","bloody bay" ,"westmooorings",
"el doraldo","rousillac34")
areas=c("arima","port of spain","chaguanas")
#Code
L=list()
for(i in 1:length(areas)){
ind=which(grepl(paste(areas[i]),df))
if(length(ind)!=0)
{
L[i]=df[ind]
df[-ind]
}
}
Вывод:
L
[[1]]
NULL
[[2]]
NULL
[[3]]
[1] "chaguanas proper"
Ответ №2:
Я думаю, что здесь было бы проще использовать sapply
:
L <- sapply(areas, function(x) grep(x, df, value = TRUE))
L
#$arima
#character(0)
#$`port of spain`
#character(0)
#$chaguanas
#[1] "chaguanas proper"
То же самое при использовании tidyverse
функций было бы :
purrr::map(areas, ~stringr::str_subset(df, .x))
Ответ №3:
Мы можем предварительно инициализировать ‘L’ с помощью length
‘areas’ и использовать if
условие, как в комментариях
L <- vector("list", length(areas))
for(i in seq_along(areas)){
ind <- grep(areas[i],df )
if(length(ind) > 0) {
L[[i]] <- df[ind]
df <- df[-ind]
}
}
L
#[[1]]
#NULL
#[[2]]
#NULL
#[[3]]
#[1] "chaguanas proper"
ПРИМЕЧАНИЕ: Это отвечает на опубликованный вопрос OP
Если мы хотим сделать это векторизованным способом, очень простой вариант (без циклов и grep
вызывается только один раз)
grep(paste(areas, collapse="|"), df, value = TRUE)
#[1] "chaguanas proper"
данные
df <- c("westmoorings east","chaguanas proper","bloody bay" ,"westmooorings",
"el doraldo","rousillac34")
areas <- c("arima","port of spain","chaguanas")
Ответ №4:
Ошибка R, которую вы видите, часто возникает, когда вы немного ошибаетесь в синтаксисе индексации. В этом случае кажется, что вы хотите выполнить цикл по элементам вашего area vector, но в вашем исходном коде вы просите R поместить возвращаемые значения на (верхний) уровень «индексирования» вашего списка «L», т. е. L[i]
. Фактически, вы должны размещать возвращаемые значения на (нижнем) уровне «значений» вашего списка «L», т. Е. L[[i]]
. Смотрите примеры:
> Output_listA <- list()
> for(i in 1:length(areas)){
Output_listA[[i]] <- grep(areas[i],df, value=TRUE)
}
> Output_listA
[[1]]
character(0)
[[2]]
character(0)
[[3]]
[1] "chaguanas proper"
В Output_listA вы видите использование grep()
с параметром «значение= TRUE». Это вернет список совпадений. Но, может быть, вы просто хотите, чтобы индекс выполнял дальнейшие манипуляции? Затем используйте grepl()
, как показано ниже:
> Output_listB <- list()
> for(i in 1:length(areas)){
Output_listB[[i]] <- grepl(areas[i],df)
}
> Output_listB
[[1]]
[1] FALSE FALSE FALSE FALSE FALSE FALSE
[[2]]
[1] FALSE FALSE FALSE FALSE FALSE FALSE
[[3]]
[1] FALSE TRUE FALSE FALSE FALSE FALSE
> df[ Output_listB[[3]] ]
[1] "chaguanas proper"
Наконец, вы можете позволить lapply()
функции выполнить всю работу за вас. Ниже grep()
показано использование, но вы могли бы так же легко использовать grepl()
:
> lapply(areas, FUN = function(x) grep(x, df, value=TRUE) )
[[1]]
character(0)
[[2]]
character(0)
[[3]]
[1] "chaguanas proper"