You can try
> library(data.table)
> Vec1 - nafill(Vec2[names(Vec1)], fill = 0)
Val1 Val2 Val3 Val4
1 -8 3 -7
Benchmarking
set.seed(0)
n1 <- 1e5
Vec1 <- setNames(sample.int(n1), paste0("v", 1:n1))
n2 <- 1e2
Vec2 <- setNames(sample.int(n2), paste0("v", sample(n1, n2)))
microbenchmark(
`M--1` = `[<-`(Vec1, names(Vec2), Vec1[names(Vec2)] - Vec2),
`M--2` = Vec1 |> replace(names(Vec2), Vec1[names(Vec2)] - Vec2),
`SamR` = rowSums(data.frame(Vec1, -Vec2[names(Vec1)]), na.rm = TRUE),
`Andre` = {
Vecs <- Vec2[names(Vec1)]
Vec1 - replace(Vecs, is.na(Vecs), 0)
},
`SAL` = {
idx <- match(names(Vec2), names(Vec1))
Vec1[idx] <- Vec1[idx] - Vec2
},
`Friede` = {
merge(data.frame(Vec1, n = names(Vec1)),
data.frame(-Vec2, n = names(Vec2)),
by = "n", all.x = TRUE
) |>
subset(select = -n) |>
rowSums(na.rm = TRUE) |> # or replace
setNames(names(Vec1))
},
`s_baldur` = ifelse(names(Vec1) %in% names(Vec2), Vec1 - Vec2[names(Vec1)], Vec1),
`Thomas` = Vec1 - data.table::nafill(Vec2[names(Vec1)], fill = 0),
unit = "relative",
times = 50L
)
and you will see the base R solution provide by @SAL is the most efficient
Unit: relative
expr min lq mean median uq max
M--1 2.513836 2.490961 2.909901 2.534369 2.738404 3.010798
M--2 2.616862 2.362815 2.629789 2.403732 2.533827 3.291382
SamR 10.188135 8.827689 10.617243 9.646134 10.883201 16.071042
Andre 4.191419 4.021243 5.773643 4.326937 5.428873 18.314273
SAL 1.000000 1.000000 1.000000 1.000000 1.000000 1.000000
Friede 232.612582 192.581732 180.411511 187.376767 177.789439 123.654579
s_baldur 7.437139 6.561556 7.051161 7.389931 7.969211 5.450089
Thomas 4.000498 3.631732 4.174856 3.677764 5.209227 3.736972
neval
50
50
50
50
50
50
50
50