【问题标题】:Sort map with (Spanish) accented words in Rcpp在 Rcpp 中使用(西班牙语)重音词对地图进行排序
【发布时间】:2015-07-21 01:35:44
【问题描述】:

虽然通过在 std::sort 中指定 UTF-8 语言环境,我可以成功地对带有重音元音的西班牙语单词进行排序,

// [[Rcpp::export]]
std::vector<std::string> sort_words(std::vector<std::string> x) {
  std::sort(x.begin(), x.end(), std::locale("en_US.UTF-8"));
  return x;
}

/*** R
words <- c("casa", "árbol", "zona", "árbol", "casa", "libro")
sort_words(words)
*/

returns (as expected):
[1] "árbol" "árbol" "casa"  "casa"  "libro" "zona"

我不知道如何对地图做同样的事情:

// slightly modified version of tableC on http://adv-r.had.co.nz/Rcpp.html
// [[Rcpp::export]]
std::map<String, int> table_words(CharacterVector x) {
  std::setlocale(LC_ALL, "en_US.UTF-8");
  // std::setlocale(LC_COLLATE, "en_US.UTF-8"); // also tried this instead of previous line
  std::map<String, int> counts;
  int n = x.size();
  for (int i = 0; i < n; i++) {
    counts[x[i]]++;
  }
  return counts;
}

/*** R
words <- c("casa", "árbol", "zona", "árbol", "casa", "libro")
table_words(words)
*/

returns:
casa    libro   zona    árbol
    2       1       1       2

but I want:
árbol   casa    libro   zona    
    2       2       1       1

关于如何让table_words 将重音“árbol”放在“casa”之前,使用 Rcpp 甚至在 R 中使用base::sort,有什么想法吗?

另外,std::sort(..., std::locale("en_US.UTF-8")) 仅在我的 Linux 机器上使用:gcc 版本 4.8.2 (Ubuntu 4.8.2-19ubuntu1)。它不适用于 Mac 10.10.3:Apple LLVM 版本 6.1.0 (clang-602.0.53)(基于 LLVM 3.6.0svn)。关于我的 Mac 编译器缺少我的 Linux 编译器的任何线索?

这是两台机器的脚本和 sessionInfo:

// [[Rcpp::plugins(cpp11)]]
#include <locale>
#include <clocale>
#include <Rcpp.h>
using namespace Rcpp;

// [[Rcpp::export]]
std::vector<std::string> sort_words(std::vector<std::string> x) {
  std::sort(x.begin(), x.end(), std::locale("en_US.UTF-8"));
  return x;
}

// [[Rcpp::export]]
std::map<String, int> table_words(CharacterVector x) {
  // std::setlocale(LC_ALL, "en_US.UTF-8"); // tried this instead of next line
  std::setlocale(LC_COLLATE, "en_US.UTF-8");
  std::map<String, int> counts;
  int n = x.size();
  for (int i = 0; i < n; i++) {
    counts[x[i]]++;
  }
  return counts;
}

/*** R
words <- c("casa", "árbol", "zona", "árbol", "casa", "libro")
sort_words(words)
table_words(words)
sort(table_words(words), decreasing = T)
output_from_Rcpp <- table_words(words)
sort(names(output_from_Rcpp))
*/

> words <- c("casa", "árbol", "zona", "árbol", "casa", "libro")

> sort_words(words)
[1] "árbol" "árbol" "casa"  "casa"  "libro" "zona" 

> table_words(words)
 casa libro  zona árbol 
    2     1     1     2 

> sort(table_words(words), decreasing = T)
 casa árbol libro  zona 
    2     2     1     1 

> output_from_Rcpp <- table_words(words)

> sort(names(output_from_Rcpp))
[1] "árbol" "casa"  "libro" "zona" 

sessionInfo on linux machine:
R version 3.2.0 (2015-04-16)
Platform: x86_64-pc-linux-gnu (64-bit)
Running under: Ubuntu 14.04 LTS

locale:
[1] en_US.UTF-8

attached base packages:
[1] stats     graphics  grDevices utils     datasets  methods   base     

loaded via a namespace (and not attached):
[1] tools_3.2.0 Rcpp_0.11.6

sessionInfo on Mac:
R version 3.2.1 (2015-06-18)
Platform: x86_64-apple-darwin13.4.0 (64-bit)
Running under: OS X 10.10.3 (Yosemite)

locale:
[1] en_US.UTF-8

attached base packages:
[1] stats     graphics  grDevices utils     datasets  methods   base     

other attached packages:
[1] textcat_1.0-3 readr_0.1.1   rvest_0.2.0  

loaded via a namespace (and not attached):
 [1] httr_1.0.0    selectr_0.2-3 R6_2.1.0      magrittr_1.5  tools_3.2.1   curl_0.9.1    Rcpp_0.11.6   slam_0.1-32   stringi_0.5-5
[10] tau_0.0-18    stringr_1.0.0 XML_3.98-1.3 

【问题讨论】:

  • 请原谅我的无知,但是std::sort 什么时候采用了第三个参数,它是一个语言环境? std::sort 的第三个参数应该是比较两个项目的函数或仿函数,而不是语言环境。
  • @PaulMcKenzie:语言环境是比较两个项目的函子。 en.cppreference.com/w/cpp/locale/locale/operator()
  • 对“Rcpp”一无所知,但您是否知道对于std::map,排序是类型本身的一部分,您需要自定义比较器来启用不同的排序?
  • @ChristianHackl 是的,我知道std::map 订购,但我不知道如何让它把带重音的单词和没有重音的单词按顺序排列,这样我就得到了 “árbol”“casa” 之前。回到std::sort,如果我只指定std::sort(x.begin(), x.end(),我会在“árbol”之前得到“casa”,但如果我指定std::sort(x.begin(), x.end(), std::locale("en_US.UTF-8")),我会得到 "casa" 之前的 "árbol",这是我想要的顺序。我的问题是如何在 std::map 中获得第二个订单(即 "árbol""casa" 之前)?

标签: c++ r sorting std rcpp


【解决方案1】:

std::map 上应用std::sort 是没有意义的,因为根据定义地图总是排序。该定义是模板实例化的具体类型的一部分。 std::map 有第三个“隐藏”类型参数,用于排序键的比较函数,默认为 std::less 键类型。见http://en.cppreference.com/w/cpp/container/map

在您的情况下,您可以使用std::locale 作为比较类型,并将std::locale("en-US")(或任何适合您的系统)传递给构造函数。

这是一个例子。它使用 C++11,但您可以轻松地在 C++03 中使用相同的解决方案。

#include <map>
#include <iostream>
#include <string>
#include <locale>
#include <exception>

using Map = std::map<std::string, int, std::locale>;

int main()
{
    try
    {
        Map map(std::locale("en-US"));
        map["casa"] = 1;
        map["árbol"] = 2;
        map["zona"] = 3;
        map["árbol"] = 4;
        map["casa"] = 5;
        map["libro"] = 6;

        for (auto const& map_entry : map)
        {
            std::cout << map_entry.first << " -> " << map_entry.second << "\n";
        }
    }
    catch (std::exception const& exc)
    {
        std::cerr << exc.what() << "\n";
    }
}

输出:

árbol -> 4
casa -> 5
libro -> 6
zona -> 3

当然,您必须意识到std::locale 高度依赖于实现这一事实。 Boost.Locale 可能会更好。

另一个问题是这个解决方案可能看起来令人困惑,因为std::locale 并不是许多程序员会与比较函数相关联的东西。这有点太聪明了。

因此可能是更易读的替代方案:

#include <map>
#include <iostream>
#include <string>
#include <locale>
#include <exception>

struct ComparisonUsingLocale
{
    std::locale locale{ "en-US" };

    bool operator()(std::string const& lhs, std::string const& rhs) const
    {
        return locale(lhs, rhs);
    }
};

using Map = std::map<std::string, int, ComparisonUsingLocale>;

int main()
{
    try
    {
        Map map;
        map["casa"] = 1;
        map["árbol"] = 2;
        map["zona"] = 3;
        map["árbol"] = 4;
        map["casa"] = 5;
        map["libro"] = 6;

        for (auto const& map_entry : map)
        {
            std::cout << map_entry.first << " -> " << map_entry.second << "\n";
        }
    }
    catch (std::exception const& exc)
    {
        std::cerr << exc.what() << "\n";
    }
}

【讨论】:

  • 感谢您的扩展帮助,但仍然没有运气:Earls-MBP:C++ earlbrown$ g++ -std=c++11 order_with_accents.cpp -o go Earls-MBP:C++ earlbrown$ ./go collate_byname&lt;char&gt;::collate_byname failed to construct for en-US Earls-MBP:C++ earlbrown$ @ 987654337@Configured with: --prefix=/Applications/Xcode.app/Contents/Developer/usr --with-gxx-include-dir=/usr/include/c++/4.2.1 Apple LLVM version 6.1.0 (clang-602.0.53) (based on LLVM 3.6.0svn) Target: x86_64-apple-darwin14.4.0 Thread model: posix
猜你喜欢
  • 2014-12-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-01-21
相关资源
最近更新 更多