2015-07-19 4 views
5

Während ich Spanisch Wörter mit akzentuierten Vokale erfolgreich sortieren kann durch einen UTF-8-Gebietsschema in std :: sort AngabeSortieren Karte mit (Spanisch), betont Wörter in 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; 
} 

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

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

Ich kann nicht herausfinden, wie

// 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 

Alle Ideen, wie table_words haben den Akzent „árbol“ setzen, bevor „casa“, mit RCPP oder sogar wieder aus in R, mit base::sort: das gleiche mit einer Karte zu tun?

Auch, std::sort(..., std::locale("en_US.UTF-8")) nur Wörter auf meinem Linux-Rechner mit: GCC-Version 4.8.2 (Ubuntu 4.8.2-19ubuntu1). Es funktioniert nicht auf dem Mac 10.10.3 mit: Apple LLVM Version 6.1.0 (clang-602.0.53) (basierend auf LLVM 3.6.0svn). Irgendwelche Hinweise darauf, was mein Mac Compiler fehlt, dass mein Linux Compiler hat?

Hier ist mein Skript und meine Session, für beiden Maschinen:

// [[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 
+1

Pardon meiner Unwissenheit, aber wann hat 'std :: sort' einen dritten Parameter nehmen, die eine locale war? Der dritte Parameter für 'std :: sort' soll eine Funktion oder ein Funktor sein, der zwei Elemente vergleicht, kein Gebietsschema. – PaulMcKenzie

+1

@PaulMcKenzie: Ein Gebietsschema ist unter anderem ein Funktor, der zwei Elemente vergleicht. http://en.cppreference.com/w/cpp/locale/locale/operator() –

+1

Ich weiß nichts über "Rcpp", aber Sie wissen, dass für eine 'std :: map' die Bestellung Teil von der Typ selbst und dass Sie einen benutzerdefinierten Komparator benötigen, um eine andere Reihenfolge zu ermöglichen? –

Antwort

1

Es ist nicht sinnvoll anzuwenden, macht std::sort auf einem std::map, weil eine Karte ist immer sortierten, per Definition. Diese Definition ist Teil des konkreten Typs, der von der Vorlage instanziiert wird. std::map hat einen dritten, "versteckten" Typparameter für die Vergleichsfunktion, die zum Bestellen von Schlüsseln verwendet wird, die standardmäßig std::less für den Schlüsseltyp ist. Siehe http://en.cppreference.com/w/cpp/container/map.

In Ihrem Fall können Sie std::locale als Vergleichstyp verwenden und std::locale("en-US") (oder was auch immer für Ihr System passt) an den Konstruktor übergeben.

Hier ist ein Beispiel. Es verwendet C++ 11, aber Sie können die gleiche Lösung in C++ 03 problemlos verwenden.

#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"; 
    } 
} 

Ausgang:

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

Natürlich müssen Sie sich der Tatsache bewusst sein, dass std::locale hoch Implementierung abhängig ist. Sie können mit Boost.Locale besser dran sein.

Ein anderes Problem ist, dass diese Lösung verwirrend aussehen kann, weil ein std::locale nicht genau etwas ist, das viele Programmierer mit einer Vergleichsfunktion assoziieren würden. Es ist fast ein bisschen zu schlau.

Daher ist eine möglicherweise lesbare Alternative:

#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"; 
    } 
} 
+0

Danke für die erweiterte Hilfe, aber immer noch kein Glück: Earls-MBP: C++ Earlbrown $ 'g ++ -std = C++ 11 order_with_accents.cpp -o gehen' Earls-MBP: C++ Earlbrown $'./Go' 'collate_byname :: collate_byname konnte für en-US nicht erstellt werden ' Earls-MBP: C++ earlbrown $' g ++ -v' 'Konfiguriert mit: --prefix =/Applications/Xcode.app/Contents/Developer/usr - with-gxx-include-dir =/usr/include/C++/4.2.1 Apple LLVM Version 6.1.0 (basierend auf LLVM 3.6.0svn) Ziel: x86_64-apple-darwin14.4.0 Gewindemodell: posix' –