翻转字符串向量中的二进制数字而不在 R 中循环

Flipping binary figures in a string vector without looping in R

我有一个大小相等的 0/1 元素向量,dna。和一个具有相同大小的类似向量,翻转。如果flip = 1,我想翻转dna向量中的相应图形。所以 0 会变成 1 而 1 会变成 0。并且没有循环来让它变快。我的真实数据集有很多数据。 以下是一些示例数据:

#input
dna  = c('0101010100', '1010101010', '1010101011')
flip = c('0100000001', '0000000000', '1000000000')

#requested answer
dna_flipped  = c('0001010101', '1010101010', '0010101011')
#first element: second and 10th character is flipped
#second element: nothing is changed
#third element: first character is changed

#try loop solution
flip_split = lapply(strsplit(flip, ''), function(x) which(x == '1'))

for (i in 1:length(dna)){
  for(j in seq_along(flip_split[[i]])){
    k = flip_split[[i]][j]
    substring(dna[[i]],k,k) = as.character(abs(1 - as.integer(substring(dna[[i]],k,k)))) 
  }
}

没有循环怎么能做到这一点?

我认为你描述的逻辑等同于逻辑异或。困难的部分是将其应用于字符串。以下应该有效,并且每个元素的向量化最少,因此您不需要遍历单个字符:

unname(unlist(Map(function(a, b) {
  paste(as.numeric(xor(as.numeric(charToRaw(a)) - 48 == 1,
                       as.numeric(charToRaw(b)) - 48 == 1)), collapse = "")
  }, a = dna, b = flip)))
#> [1] "0001010101" "1010101010" "0010101011"

或者,也许更有效,正如 Ritchie Sacramento 指出的那样:

unname(unlist(Map(function(a, b) {
  rawToChar(as.raw(as.numeric(xor(as.numeric(charToRaw(a)) - 48 == 1,
                       as.numeric(charToRaw(b)) - 48 == 1)) + 48))
  }, a = dna, b = flip)))
#> [1] "0001010101" "1010101010" "0010101011"