How to round/format a vector of numbers dynamically without using a loop?

Viewed 105

I have two vectors of numbers: v1 and v2 The first is a set of real numbers. The second is a set of decimal places that I want to round or format v1.

Here are the vectors:

v1 <- c(7.449835, 6.649058, 9.072736, 5.643506, 8.979166, 5.544238, 1.746717, 4.151327, 8.408533, 1.176206)
v2 <- c(1, 2, 0, 3, 4, 6, 1, 2, 2, 3)

The result I want is this:

[1] 7.4 6.64 9 5.643 8.9791 5.544238 1.7 4.15 8.40 1.176

...where the first vector is rounded/formatted according to the second vector. I don't care if the result is a character or number vector. But in the end, there are a lot of numbers and I don't want to use a loop:

Notice that this doesn't work:

format(v1, digits = v2)
 [1] "7" "7" "9" "6" "9" "6" "2" "4" "8" "1"

And this doesn't work:

round(v1, digits = v2)
[1] 7.400000 6.650000 9.000000 5.644000 8.979200 5.544238 1.700000 4.150000 8.410000 1.176000

So, how can I dynamically round or format a vector without using a loop in R?

3 Answers

The ?sprintf fmt argument can take "a character vector of format strings".

So you can piece the formats together by pasting the format digits vector with the sprintf format syntax e.g. paste0("%#.", v2, "f").

All together

sprintf(v1, fmt=paste0("%#.", v2, "f"))

You can use round, then remove the trailing zeros as suggested in this answer

v1 <- c(7.449835, 6.649058, 9.072736, 5.643506, 8.979166, 5.544238, 1.746717, 4.151327, 8.408533, 1.176206)
v2 <- c(1, 2, 0, 3, 4, 6, 1, 2, 2, 3)
v1 <- round(v1, digits = v2)
v1 <- sub("0+$", "", as.character(v1))

If you round first and then apply as.character you get the desired output:

mapply(function(x,y){as.character(round(x,y))}, v1, v2)
#[1] "7.4"      "6.65"     "9"        "5.644"    "8.9792"   "5.544238" "1.7"      "4.15"     "8.41"     "1.176"   

# to get without quotes use `cat` or `print( ... , quote=FALSE)`
cat( mapply(function(x,y){as.character(round(x,y))}, v1, v2))
#7.4 6.65 9 5.644 8.9792 5.544238 1.7 4.15 8.41 1.176
Related