将字符串与“==”进行比较的意外结果
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 FALSE
、NA
和 NULL
给出不同的结果)。
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
调整为 max
imum 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"
我有两个向量:
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 FALSE
、NA
和 NULL
给出不同的结果)。
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
调整为 max
imum 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"