user8102905
user8102905

Reputation: 191

Sum of digits in a numeric matrix per row

Having a matrix like:

        [,1] [,2] [,3] [,4] [,5] [,6]
   [1,]   11   14   17   20   23   26
   [2,]   12   15   18   21   24   27
   [3,]   13   16   19   22   25   28

I want to get only the rows that have sum of digits for each row between 2 values.

Sum of digits for each row:

   [1] 30
   [2] 38
   [3] 42

so if I want to get only rows where sum of digits is between 31 and 40, then only the row 2 with value 38 must be returned.

Upvotes: 4

Views: 162

Answers (2)

989
989

Reputation: 12935

You could do:

l <- strsplit(as.character(t(m)), "")
mx <- max(lengths(l))
res <- rowSums(matrix(as.numeric(unlist(lapply(l, 'length<-', mx))), 
              ncol = ncol(m)*mx, byrow = TRUE), na.rm = TRUE)
m[res>31 & res<42,]

#[1] 12 15 18 21 24 27
  • l is the list of all digits in m
  • mx is the maximum length of a number in m just in case the number of digits are not equal for all numbers within m (for your case it is 2)

  • Then you make all list elements of equal length (by adding NA) and getting a matrix out of list elements where rowSums gives you the sum of digits per row in m

  • Once you have the row-sum of digits (i.e., res), you filter out those rows of interest.

Upvotes: 0

akrun
akrun

Reputation: 887501

We can do

 i1 <-  apply(m1, 1, function(x) {
         v1 <- sum(unlist(lapply(strsplit(as.character(x), ""), as.numeric)))
         v1 > 31 & v1 < 40})

m1[i1, , drop = FALSE]
#   [,1] [,2] [,3] [,4] [,5] [,6]
#[1,]   12   15   18   21   24   27

Or

i1 <- sapply(strsplit(do.call(paste0, as.data.frame(m1)), ""), 
               function(x) sum(as.integer(x)))
m1[i1, , drop = FALSE]

Or we can do

f1 <-  Vectorize(function(x) sum(floor(x / 10^(0:(nchar(x) - 1))) %% 10))
i1 <-  rowSums(t(apply(m1, 1, f1))) %in% 31:40
m1[i1, , drop = FALSE]

data

m1 <- matrix(11:28, nrow = 3)

Upvotes: 3

Related Questions