将字符串与“==”进行比较的意外结果

Unexpected result comparing strings with `==`

我有两个向量:

a = strsplit("po","")[[1]]
[1] "p" "o"

b = strsplit("polo","")[[1]]
[1] "p" "o" "l" "o"

我正在尝试使用 == 来比较它们。 不幸的是,a==b 给出了意想不到的结果。

a==b
[1]  TRUE  TRUE FALSE  TRUE

虽然我希望有:

[1]  TRUE  TRUE FALSE  FALSE

那么,这是什么原因造成的?怎样才能达到预期的效果?

问题似乎与两个向量的最后一个元素与将 b 更改为例如相同这一事实有关polf 确实给出了预期的结果,而且因为将 b 设置为 pooo 给出了 TRUE TRUE FALSE TRUE 而不是 TRUE TRUE TRUE TRUE.

编辑

换句话说,我希望缺失的元素(当长度不同时)被当作空值传递(只有 "" 似乎给出 TRUE TRUE FALSE FALSENANULL给出不同的结果)。

c("p","o","","")==c("p","o","l","o")
[1]  TRUE  TRUE FALSE FALSE

您在这里遇到的问题是由于回收(不是环保型)造成的。当对两个需要相同长度的向量应用操作时,R 通常会自动循环或重复较短的向量,直到它的长度足以匹配较长的向量。您意想不到的结果是由于 R 将向量 c("p", "o") 回收为长度 4(较大向量的长度)并实质上将其转换为 c("p", "o", "p", "o")。如果我们比较 c("p", "o", "p", "o")c("p", "o", "l", "o") 我们可以看到我们得到了上面意想不到的结果:

c("p", "o", "p", "o") == c("p", "o", "l", "o")
#> [1]  TRUE  TRUE FALSE  TRUE

我不太清楚为什么您会期望结果是 TRUE TRUE FALSE FALSE,因为将长度为 2 的向量与长度为 4 的向量进行比较并回收长度有点含糊不清-2 向量(这是 R 正在做的)似乎是除了抛出错误之外最合理的默认值。

为了得到 OP 中显示的结果,我们可以将两个向量放在 list 中,将它们的 length 调整为 maximum lengths(通过添加 NA's) 并测试比较是否为 %in% TRUE.

list(a, b) |>
  (\(.) lapply(., `length<-`, max(lengths(.))))() |>
  (\(.) do.call(\(x, y, ...) (x == y) %in% TRUE, .))()
# [1]  TRUE  TRUE FALSE FALSE

注: R version 4.1.2 (2021-11-01)


数据:

a <- c("p", "o")
b <- c("p", "o", "l", "o")

如果任何字符串在 strsplit[= 之前​​的字符数较少,我们可以创建一个函数来在 right 上填充 space (stringr::str_pad) 16=]

checkStrings <- function(s1, s2) {
   n1 <- nchar(s1)
   n2 <- nchar(s2)
   if(n1 != n2) {
      n <- max(n1, n2)
     i1 <- which.min(c(n1, n2))
     if(i1 == 1) {
       s1 <- stringr::str_pad(s1, width = n, pad = " ", side = "right")
      } else {
      s2 <- stringr::str_pad(s1, width = n, pad = " ", side = "right")
      }
    }
   s1v <- strsplit(s1, "")[[1]]
   s2v <- strsplit(s2, "")[[1]]
   return(s1v == s2v)
   
}

-测试

> checkStrings(str1, str2)
[1]  TRUE  TRUE FALSE FALSE

数据

str1 <- "po"
str2 <- "polo"

另一种解决问题的方法是创建一个向量 length(b)replace 第一个值 a:

a <- replace(character(length(b)), seq(a), a)
a
# [1] "p" "o" ""  ""

然后我们可以使用 ==:

适当地比较两个向量
a==b
# [1]  TRUE  TRUE FALSE FALSE

character(length(b)) 创建 length(b)"" 向量。 vector(,length(b)) 是另一种选择,但它会创建一个 FALSE 的向量。

如果想在两个或更多字符串上执行此操作,可能的函数是:

matchLength = function(strings){
  l = lapply(strings,\(x) strsplit(x,"")[[1]])
  larger = which.max(lengths(l))
  lapply(l, function(x) replace(character(length(l[[larger]])), seq(x), x))
}

这给出了所需的输出:

strings=c("po","polo","polka")
matchLength(strings)

# [[1]]
# [1] "p" "o" ""  ""  "" 
# 
# [[2]]
# [1] "p" "o" "l" "o" "" 
# 
# [[3]]
# [1] "p" "o" "l" "k" "a"