【问题标题】:vectorised comparison of strings to single value in RcppRcpp中字符串与单个值的向量化比较
【发布时间】:2021-03-31 22:11:25
【问题描述】:

在将数值向量与单个值进行比较时,Rcpp 中的 == 运算符按预期工作。 IE。向量的每个元素都与值进行比较,并返回一个逻辑向量。例如,考虑以下行为符合预期:

library(Rcpp)
cppFunction('
CharacterVector test_vals(NumericVector x) {
  if (is_true(any(x == 3))) return ("Values include 3");
  return ("3 not found");
}')
test_vals(1:2)
# [1] "3 not found"
test_vals(1:5)
# [1] "Values include 3"

但是,如果我尝试将字符向量与字符标量进行比较,它似乎只测试了向量的第一个元素:

cppFunction('
CharacterVector test_names(NumericVector x) {
  CharacterVector y = x.attr("names");
  if (is_true(any(y == CharacterVector::create("foo")))) return ("Names include foo");
  return ("foo not found");
}')
test_names(c(a=1, b=2, foo=3))
# [1] "foo not found"
test_names(c(foo=3, a=1, b=2))
# [1] "Names include foo"

我知道比较两个相同长度的字符向量似乎以向量化的方式工作,正如预期的那样:

cppFunction('
CharacterVector test_names(NumericVector x) {
  CharacterVector y = x.attr("names");
  CharacterVector foo(x.size());
  foo.fill("foo");
  if (is_true(any(y == foo))) return ("Names include foo");
  return ("foo not found");
}')
test_names(c(a=1, b=2, foo=3))
# [1] "Names include foo"
test_names(c(foo=3, a=1, b=2))
# [1] "Names include foo"
test_names(c(a=1, b=2))
# [1] "foo not found"

这是否意味着字符向量与单个值的比较尚未在 Rcpp 中实现,还是我只是想念如何做到这一点?

【问题讨论】:

  • 好问题。看起来NumericVector 有合适的opeator=()CharacterVector 可能没有(因为角色通常是不同的鱼牛)。我们可能会添加它;与此同时,您可能可以为自己编写一个“手动”处理两个向量的小帮手。
  • 所以说白了,你想要一个'contains()'操作符,它接受一个字符串向量和一个字符串,返回一个布尔值?由于此处的多对一映射,将其表述为== 对我的阅读来说有点“偏离”。您真的在这里查看集合运算符,对吗? (我和你一样,std::vector<> 是最好的容器......)
  • 是的 - 这正是我正在寻找的
  • 我认为我们应该看看其他东西——想想std::vector<std::string> 并将其交给已经执行此操作的 STL...
  • 很高兴这有帮助。更多地考虑缺乏== 支持:我们通常不会像 R 那样“回收”(某些语言称之为“广播”)。所以“多对一”的比较有点未知。

标签: r rcpp


【解决方案1】:

在我们的快速讨论之后,这里是一个非常简单的解决方案,因为问题(如提出的那样)很简单——没有正则表达式,没有花哨。只需遍历所有元素并在找到匹配项后立即返回,否则使用false 保释。

代码

#include <Rcpp.h>

// [[Rcpp::export]]
bool contains(std::vector<std::string> sv, std::string txt) {
    for (auto s: sv) {
        if (s == txt) return true;
    }
    return false;
}

/*** R
sv <- c("a", "b", "c")
contains(sv, "foo")
sv[2] <- "foo"
contains(sv, "foo")
*/

演示

> Rcpp::sourceCpp("~/git/stackoverflow/66895973/answer.cpp")

> sv <- c("a", "b", "c")

> contains(sv, "foo")
[1] FALSE

> sv[2] <- "foo"

> contains(sv, "foo")
[1] TRUE
> 

这实际上只是在寻找我们在(大约)100k 行 Rcpp 中可能已经拥有的内容,或者 STL 可能拥有的内容之前从臀部开始拍摄......

这同样适用于您之前的命名属性示例,当然,使用CharacterVector 和/或使用从它到我们在此处使用的std::vector&lt;std::string&gt; 的转换,或者...如果你有一个旧的编译器,将 for 从 C++11 风格切换到 K+R 风格。

【讨论】:

  • 我认为Rcpp 等价物是将Rcpp::StringRcpp::StringVector 的每个元素进行比较(?)
  • 我们可能有这个。我不确定。正如我在上面所写的,将两行代码拼凑在一起比在文档的煤矿中挖掘要快...
  • 归根结底,这是 例如 data.table 已经做得很好的事情之一,所以我不太担心。 例如quanteda 团队更多地使用文本数据的人可能知道更多。
猜你喜欢
  • 1970-01-01
  • 2015-01-22
  • 1970-01-01
  • 2016-07-27
  • 2015-09-28
  • 1970-01-01
  • 2015-11-19
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多