количество элементов для замены, не кратное ошибке длины замены

#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"