【发布时间】:2016-06-03 20:32:32
【问题描述】:
假设如果我们有一个数字 1.000633,我想计算小数点后的零个数,直到分数中的第一个非零数字,答案应该是 3。对于 0.002,答案应该是 2。
R 中没有这样的函数可以提供帮助。我已经探索了 DescTools 包中的 Ndec 函数,但它没有完成这项工作。
【问题讨论】:
假设如果我们有一个数字 1.000633,我想计算小数点后的零个数,直到分数中的第一个非零数字,答案应该是 3。对于 0.002,答案应该是 2。
R 中没有这样的函数可以提供帮助。我已经探索了 DescTools 包中的 Ndec 函数,但它没有完成这项工作。
【问题讨论】:
使用rle函数:
#test values
x <- c(0.000633,0.003,0.1,0.001,0.00633044,10.25,111.00012,-0.02)
#result
sapply(x, function(i){
myNum <- unlist(strsplit(as.character(i), ".", fixed = TRUE))[2]
myNumRle <- rle(unlist(strsplit(myNum, "")))
if(myNumRle$values[1] == 0) myNumRle$lengths[1] else 0
})
#output
# [1] 3 2 0 2 2 0 3 1
【讨论】:
我们可以使用sub
ifelse(grepl("\\.0", str1),
nchar(sub("[^\\.]+\\.(0+)[^0]+.*", "\\1", str1)), NA)
#[1] 3 2 3 3 2
或使用stringi
library(stringi)
r1 <- stri_extract(str1, regex="(?<=\\.)0+")
ifelse(is.na(r1), NA, nchar(r1))
#[1] 3 2 3 3 2
只是为了检查它是否适用于任何奇怪的情况
str2 <- "0.00A-Z"
nchar(sub("[^\\.]+\\.(0+)[^0]+.*", "\\1", str2))
#[1] 2
str1 <- as.character(c(1.000633, 0.002, 0.000633,
10.000633, 3.0069006))
这是另一种可能性:
zeros_after_period <- function(x) {
if (isTRUE(all.equal(round(x),x))) return (0) # y would be -Inf for integer values
y <- log10(abs(x)-floor(abs(x)))
ifelse(isTRUE(all.equal(round(y),y)), -y-1, -ceiling(y))} # corrects case ending with ..01
例子:
x <- c(1.000633, 0.002, -10.01, 7.00010001, 62.01)
sapply(x,zeros_after_period)
#[1] 3 2 1 3 1
【讨论】:
ifelse(round(y) == y, -y-1, -ceiling(y)) ?
x <- c(0.1, 1.0, 1.001)
使用stringr 包中的str_count 的另一种方式,
x <- as.character(1.000633)
str_count(gsub(".*[.]","",x), "0")
#[1] 3
编辑:这会计算小数点后的所有零,直到第一个非零值。
y <- c(1.00215, 1.010001, 50.000809058, 0.1)
str_count(gsub(".*[.]","",gsub("(?:(0+))[1-9].*","\\1",as.character(y))),"0")
#[1] 2 1 3 0
【讨论】:
使用regexpr 及其match.length 参数
attr(regexpr("(?<=\\.)0+", x, perl = TRUE), "match.length")
【讨论】:
x <- 10.2,这将返回-1 而不是0。我必须在我的解决方案中插入一个ifelse 语句来捕获没有它会失败的情况。这可能是您认为我的实现复杂的原因。另一方面,也许您也可以考虑捕获此类案例,以便您的解决方案也适用于任何数量。
-1 不匹配。那是不匹配的regexpr 表示法。我的解决方案适用于 任何 号码。
(?<=\\.)0+|$ 作为正则表达式,如果你想得到 0 而不是 -1。
floor( -log10( eps + abs(x) - floor( abs( x ) ) ) )
【讨论】:
count0 <- function(x, tol = .Machine$double.eps ^ 0.5) { x <- abs(x); y <- -log10(x - floor(x)); floor(y) - (y %% 1 < tol) }
您可以使用sub,因为我们不需要跳转。因此不需要gsub
nchar(sub(".*\\.(0*).*","\\1",str1))
[1] 3 2 3 3 2
在哪里
str1 <- as.character(c(1.000633, 0.002, 0.000633,
10.000633, 3.0069006))
【讨论】: