【问题标题】:Unexpected result comparing strings with `==`将字符串与 `==` 进行比较的意外结果
【发布时间】:2022-01-25 17:30:08
【问题描述】:

我有两个向量:

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

【问题讨论】:

  • 为了得到FALSE,“l”和“o”是什么意思?
  • @jpdugo17 我编辑了我的答案以使其更清晰。在某种程度上,我希望将“l”和“o”与什么都没有比较,所以基本上总是返回F

标签: r string string-comparison


【解决方案1】:

您在这里遇到的问题是由于回收(不是环保的那种)。当对要求它们具有相同长度的两个向量进行操作时,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 正在做的)似乎是除了抛出错误之外最合理的默认设置。

【讨论】:

  • 我编辑了我的答案以使其更清晰。我希望在某种程度上将“l”和“o”与什么都没有比较,所以基本上总是返回F
【解决方案2】:

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

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")

【讨论】:

    【解决方案3】:

    如果任何字符串在strsplit 之前的字符数较少,我们可以创建一个函数来在right 上填充空格(stringr::str_pad

    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"
    

    【讨论】:

      【解决方案4】:

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

      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"
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2011-04-04
        • 1970-01-01
        • 1970-01-01
        • 2016-08-01
        • 1970-01-01
        • 2012-05-12
        • 2012-10-06
        • 2019-01-22
        相关资源
        最近更新 更多