Em R, suponha que eu tenha um vetor como:
vector<-c("Red", " ", "", "5", "")
Quero contar quantos elementos deste vetor são apenas strings vazias que consistem apenas em espaços ou nenhum espaço . Para este vetor muito curto, são apenas três . O segundo, terceiro e quinto elementos são apenas espaços ou nenhum espaço. Eles não possuem caracteres como letras, números, símbolos, etc.
Existe alguma função ou método que conte isso? Eu queria algo que pudesse usar em vetores maiores, em vez de apenas observar cada elemento do vetor.
Mais uma opção:
E uma variação concisa da resposta anterior:
Finalmente... já que estamos nos divertindo com benchmarks. Há espaço para melhorias em relação à base R, conforme mostrado por SamR usando stringi. Aqui está outro exemplo usando Rcpp onde evitamos modificar o vetor e inspecionamos caractere por caractere até o primeiro caractere sem espaço.
Abordagens R puras
Você tem várias respostas excelentes de base R. Notei que você marcou
stringr
. Não acho que haja vantagem em usarstringr
aqui. No entanto, pode haver uso do pacote R para processamento de string/texto rápido, portátil, correto, consistente e conveniente em qualquer localidade ou codificação de caracteres.stringi
stringi
tende a ser extremamente rápido.stringr
dependestringi
(e de fato muitasstringr
funções são wrappers finos parastringi
funções), portanto, se você instaloustringr
, também terá ostringi
.Ao contrário de
stringr
,stringi
tem uma função para verificar strings vazias (equivalente a!base::nzchar()
), o que provavelmente é mais rápido que a comparação de strings e quase certamente mais rápido que contar os caracteres de todas as strings (incluindo as não vazias).Abordagens RCPP
Como a resposta de S. Baldur demonstra agora, você
Rcpp
também pode usar para isso.Isso é tão mais rápido que vou incluí-lo em uma seção separada de benchmarks abaixo, para que seja mais fácil ver as diferenças nas abordagens R puras.
Benchmarks de R puro
Só por diversão, fiz alguns benchmarks com vetores de até 1m de comprimento. A segunda abordagem de S. Baldur é mais rápida para vetores de comprimento 10 e 100. Com vetores de comprimento 1000 e superiores, a
stringi
abordagem é a mais rápida.Se a RAM for um fator, a resposta de Ben Bolker usa consistentemente menos memória. Aqui estão os dados em formato tabular (observe que os tempos são relativos e a abordagem de memória mais rápida/menor é sempre
1
).Código de referência:
Rcpp
benchmarksIncluo separadamente uma referência da
count_empty_cpp()
função de S. Baldur. Isso é muito mais rápido do que minhastringi
abordagem, então adicionei outraRcpp
função usando a biblioteca padrão C++, baseada fortemente na resposta à pergunta C++, Maneira eficiente de verificar se std::string possui apenas espaços .Também adicionei uma terceira
Rcpp
função que analisa a expressão S subjacente de cada elemento do vetor de caracteres. Isso significa que podemos evitar a conversão de tipo nos casos em que a string está vazia. Além disso, quando precisamos examinar o conteúdo da string, eu usoCHAR()
para converter oSEXP
ponteiro em estilo C para uma string terminada em nulo (const char*
), em vez de um C++std::string
. Isso significa que copiamos a referência (provavelmente 8 bytes por string), em vez dos dados.Comparei isso com as duas respostas R mais rápidas. Todas
Rcpp
as abordagens são muito mais rápidas do que as abordagens R mais rápidas, uma vez que os comprimentos dos vetores são>1e4
.Aqui está uma tabela de resultados. Há muito poucas diferenças entre as duas primeiras
Rcpp
abordagens. A abordagem evitandostd::string
é um pouco mais rápida que as outras duas:Estas são strings relativamente curtas. Não vou executar mais benchmarks, mas suspeito que se as strings fossem mais longas, veríamos um benefício relativo em copiar o ponteiro em vez dos dados.
Uma nota sobre os benchmarks
Esses benchmarks são principalmente para diversão. As diferenças entre todas as respostas são relativamente pequenas, portanto, a menos que você repita isso muitas vezes com vetores enormes, tenha strings extremamente longas ou recursos de memória muito limitados, em vez de lançar minha própria solução Rcpp que é nanossegundos mais rápida, eu otimizaria para código legível .
Para golfe com código, provavelmente você pode estar interessado
Use
sum(grepl())
mais uma expressão regular apropriada:^
: início da string*
: zero ou mais espaços$
: fim da stringSe você quiser procurar por "espaço em branco" de forma mais geral (por exemplo, permitindo tabulações), use
"^[[:space:]]*$"
, embora, como apontado em?grep
, a definição de espaço em branco dependa da localidade ...length(grep(...))
também funcionaria, oustringr::str_count(vector, "^ *$")
.Pelo que vale:
(@RuiBarradas não incluído porque é semelhante ao @KonradRudolph). Estou surpreso que a resposta de @s_baldur seja tão rápida ... mas provavelmente também vale a pena ter em mente que esta operação será rápida o suficiente para não se preocupar com eficiência, a menos que seja uma grande parte do seu fluxo de trabalho geral ...
Eu usaria
nzchar()
em combinação comtrimws()
(mesmo que a dupla negação!nzchar()
torne isso um pouco estranho de ler):trimws
remove todos os espaços em branco. Entãonchar
obterá o número de caracteres. Compare com zero e conte apenas esses. Mas isso é cerca de 3 vezes mais lento que a resposta de Ben Bolker .Criado em 30/06/2024 com reprex v2.1.0
Editar
Com base em um comentário agora excluído,
Criado em 30/06/2024 com reprex v2.1.0