Digit sum function in R
This should be better:
digitsum <- function(x) sum(floor(x / 10^(0:(nchar(x) - 1))) %% 10)
Function for summing digits using R
One loop-less option is to use cSplit from the splitstackshape package to separate your number into a vector with one element per character, then add up all the elements in the vector. This works for 1 (single_num
) or many
numbers.
library(splitstackshape)
single_num <- 17692
many <- c(12345, 678910, 222, 10, 7099998)
sums <- function(vec) {
print(rowSums(cSplit(as.data.frame(vec),1, sep = '', stripWhite = FALSE), na.rm = T))
}
sums(single_num)
==> 25
sums(many)
==> 15 31 6 1 51
- install and load the splitstackshape package
- convert the value or vector given to a dataframe
- use the cSplit function on column 1 with an empty separator to create a column with a df for each character (colnames automatically added by cSplit)
- calculate the sum across each row and print
If you put in one number there'll be one row and one result, whereas if you put in a vector of multiple numbers there'll be that many rows and results.
na.rm = T
is needed when you put in values with different numbers of characters, because otherwise the shorter ones will end up with NAs in the later columns and rowSums()
will return NA.
Large number digit sum
You need arbitrary precision numbers. a^b
with R's numerics (double precision floats) can be only represented with limited precision and not exactly for sufficiently large input.
library(gmp)
a <- as.bigz(13)
b <- as.bigz(67)
sum(as.numeric(strsplit(as.character(a^b), split = "")[[1]]))
#[1] 328
Recursive function sum of digits R
In R, it is recommended to use Recall
for creating a recursive function.
I am using @d.b's function, but demonstrating with Recall
getSum = function( i )
{
if (nchar(i) == 1){
return(i)
} else if (i < 0 ) {
"Please enter a positive number"
}else {
print(i)
Recall( i = floor(i/10)) +i%%10
}
}
getSum(0)
# [1] 0
getSum(1)
# [1] 1
getSum(-1)
# [1] "Please enter a positive number"
getSum(5)
# [1] 5
getSum(100)
# [1] 100
# [1] 10
# [1] 1
getSum( 23)
# [1] 23
# [1] 5
Sum of digits in a numeric matrix per row
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)
Weighted sum of digits in R
> number <- 1059
> x <- strsplit(as.character(number), "")[[1]]
> y <- seq_len(nchar(number))
> as.numeric(as.numeric(x) %*% y)
[1] 52
Function for multi-level Harshad Number in R
In the meantime I made some progress in simplifying and generalizing the Harshad function:
# Function to calculate the n-leveled Harshad Numbers for given integer number intervall
multi.step.harshed.number = function(numlevels, start, end)
{
digitsum = function(x) sum(floor(x / 10^(0:(nchar(x) - 1))) %% 10)
checkinteger = function (x) {
ifelse (x == as.integer(x), return (x), return(NA))
}
db = data.frame(start:end)
for (i in 1:numlevels) {
db[, (2*i)] = sapply(db[, (2*i)-1], FUN=digitsum)
db[, (2*i)+1] = db[, (2*i)-1] / db[, (2*i)]
db[, (2*i)+1] = sapply(db[, (2*i)+1], FUN=checkinteger)
db = na.omit(db)
if (nrow(db) == 0) break
}
return(db[,1])
}
EDIT: 2nd version - maybe following code is a bit more elegant and less busy:
multi.step.harshed.number = function(numlevels, start, end) {
is.integer= function(x) ifelse (x== as.integer(x), return (x), return(NA))
digitsum = function(x) sum(floor(x/10^(0:(nchar(x)-1))) %% 10)
digitsumratio= function(x) ifelse(is.integer(x/digitsum(x)), x/digitsum(x), NA)
multi.digitsumratio= function(iter, x) {
for (i in 1:iter) x= digitsumratio(x)
return (ifelse(is.na(x), FALSE, TRUE))
}
sequence=start:end
idx=sapply(sequence, FUN=function (x) multi.digitsumratio(numlevels, x))
sequence[idx]
}
EDIT: 3rd version - same as 2nd but just faster due to use of parallel package:
multi.step.harshed.number = function(numlevels, start, end) {
library(parallel)
processors= detectCores()
cl= makeCluster(processors)
is.integer= function(x) ifelse (x== as.integer(x), return (x), return(NA))
digitsum = function(x) sum(floor(x/10^(0:(nchar(x)-1))) %% 10)
digitsumratio= function(x) ifelse(is.integer(x/digitsum(x)), x/digitsum(x), NA)
multi.digitsumratio= function(iter, x) {
for (i in 1:iter) x= digitsumratio(x)
return (ifelse(is.na(x), FALSE, TRUE))
}
sequence=start:end
idx=parSapply(cl=cl,X=sequence, FUN=function (x) multi.digitsumratio(numlevels, x))
sequence[idx]
}
Trying: multi.step.harshed.number(42, 100, 10000)
returns:
[1] 100 108 120 162 180 200 210 216 240 243 270 300 324 360 378 400 405 420 432 450
[21] 480 486 500 540 600 630 648 700 720 756 800 810 840 864 900 972 1000 1080 1200 1296
[41] 1458 1620 1800 1944 2000 2100 2160 2400 2430 2700 2916 3000 3240 3402 3600 3780 4000 4050 4200 4320
[61] 4374 4500 4800 4860 5000 5400 5832 6000 6300 6480 6804 7000 7200 7290 7560 8000 8100 8400 8640 8748
[81] 9000 9720 10000
Related Topics
In R, How to Check If Two Variable Names Reference the Same Underlying Object
Change Plotly Chart Y Variable Based on Selectinput
Overlay Geom_Points() on Geom_Boxplot(Fill=Group)
Time Series Plot with X Axis in "Year"-"Month" in R
Legends for Multiple Fills in Ggplot
Dual Y Axis in Ggplot2 for Multiple Panel Figure
Finding Where Two Linear Fits Intersect in R
How to Train a Ml Model in Sparklyr and Predict New Values on Another Dataframe
Find Consecutive Values in Vector in R
In Read.Table(): Incomplete Final Line Found by Readtableheader
Extract First Word from a Column and Insert into New Column
Minus Operation of Data Frames
Assigning by Reference into Loaded Package Datasets
R: Calculate Cosine Distance from a Term-Document Matrix with Tm and Proxy