count even numbers in a list or vector in R

Viewed 753

I'm trying to print the count the even number in a list via a loop, I don't get any results, I tried: assign numbers into a:

a<-31415926535427577896091736371787214684409012249534301465495853710507922796892589235420199561121290219608640344181598136297747713099605187072113499999983729780499510597317328160963185950244594553469083026425223082533446850352619311881710100031378387528865875332083814206171776691473035982534904287554687311595628638823537875937519577818577805321712268066130019278766111959092164201989380952572010654858632788659361533"

Then I split them:

a.c<-strsplit(piestring.c, "")

Then I unlist them:

a.cu<-unlist(piestring.c, recursive = TRUE, use.names = TRUE)

Then I convert them to numerical:

a.cn<-as.numeric(a.cu)

Then I checked if it can get even numbers:

for (stev in piestring.cn) {
    if (stev %% 2 == 0) {
    print(stev)
        }
}

Then I tried to set counter:

counter <- 0
for (stev in a.cn) {
    if (sten %% 2 == 0) {
        counter <- counter + 1
    }
}

I get no results, is there an easier way to count the even number, then print the count of the even number in the first 50 digits?

3 Answers

If you are interested in single digit even numbers, you can the stringr library:

str_count(a, "0|2|4|6|8")

[1] 186

If you are interested in the first 50 numbers:

str_count(str_sub(a, 1, 50), "0|2|4|6|8")

[1] 22

Using a similar workflow to what you are using, you can use this to check the first 50 numbers. This uses all the same logic but adds fixed = TRUE to strsplit() for a small speed increase, and takes more advantage of vectorization.

sum(as.integer(strsplit(a, "", fixed = TRUE)[[1]])[1:50] %% 2 == 0)
[1] 22

I added a new solution which using only base R functions (gregexpr) and it seems to be most efficient:

length(gregexpr("0|2|4|6|8", substr(a, 1, 50))[[1]])

OP comments suggesting that a proper function should be offered for him:

count_str <- function(x, what, first = NULL) {
stopifnot(is.vector(x))
stopifnot(is.character(what))
stopifnot(is.null(first) || is.numeric(first))
x <- unlist(x)
pattern <- paste0(what, collapse = "|")
length(gregexpr(pattern, if (is.null(first)) x else substr(x, 1, first))[[1]])
}

> count_str(a, c("0","2","4","6","8"), first = 50)
[1] 22
> count_str(a, c("0","2","4","6","8"))
[1] 186
> count_str(list(a), c("0","2","4","6","8"), first = 50)
[1] 22
> count_str(a, c("0","2","4","6","8"), first = 0)
 Error in count_str(a, c("0", "2", "4", "6", "8"), first = 0) : 
  is.null(first) || (is.numeric(first) && (first > 0)) is not TRUE 
> microbenchmark::microbenchmark(
+ base = {length(gregexpr("0|2|4|6|8", substr(a, 1, 50))[[1]])}, 
+ stringi = {stri_count(stri_sub(a, 1, 50), regex = "0|2|4|6|8")}, 
+ stringr = {sum(str_count(str_sub(a, 1, 50), "0|2|4|6|8"))}, 
+ times = 10000)
Unit: microseconds
    expr    min      lq     mean  median     uq      max neval
    base 10.665 12.2195 15.16829 12.8520 13.636 520.857 10000
 stringi 11.858 12.6705 14.66833 13.5395 14.367  312.927 10000
 stringr 13.517 14.3300 16.49280 15.2950 16.030  218.752 10000
Related