arma :: find_unique如何确定唯一索引?

时间:2016-08-11 17:56:28

标签: c++ rcpp armadillo

我正在使用arma::find_unique,我认为它返回了向量中每个唯一值首次出现的索引,但它似乎返回了其他内容。

这是一个玩具功能:

// [[Rcpp::export]]
arma::uvec test(arma::vec& x_) {
  vec x=arma::sort(x_);
  return arma::find_unique(x);
}

如果我使用简单向量test(5:1)运行R中的函数,我会得到所有索引0,1,2,3,4的向量,这是有意义的,因为每个值都是唯一的。

如果我尝试这样的话:

set.seed(1991)
var=sample(1:8,20,TRUE)
test(var)

输出:

  

1,3,6,7,19,12,14,18。

除了第一个值之外,所有这些值都是有意义的。为什么索引1处的第一个唯一值而不是0?很明显,我误解了arma::find_unique打算做什么,所以如果有人能够启发我,我将不胜感激。

修改 我的会话信息

sessionInfo()

1 个答案:

答案 0 :(得分:2)

好的,以下是@nrussell的礼貌,这个男人很棒,并在评论中给出了这个“答案”。 (我不配得到复选标记,也不值得赞成。)

  

实际上,我很确定这只是对Armadillo文档的误解,它从来没有真正保证使用稳定的排序,就像@Carl所期望的那样。在下面,std :: sort是being called,其中不能保证是C ++标准的稳定排序;还说here

     
    

“不保证保留相等元素的顺序。”

  
     

我可以演示这个here,复制犰狳算法中的"packet" structure用法。我的猜测是libc++(通常由OS X使用)确实将std::sort实现为稳定排序,而libstdc++则没有。{/ p>

轮到我:稳定排序,或维持具有相同键(即值)的记录的相对顺序,是这个问题背后的关键问题。例如,请考虑以下事项:

dog car pool dig

使用稳定排序按第一个字母排序可以得到:

car dog dig pool

因为“dog”这个词出现在向量中的“dig”之前,所以它必须出现在输出中的“dig”之前。

使用不稳定排序按第一个字母排序可以得到:

car dig dog pool

car dog dig pool

委托人与数字相关,因为每个密钥生成在字面上都存在于其他地方。所以,我们有:

2, 3, 2, 4

因此,当找到唯一值时:

2, 3, 4

2可以将id设为0或2.

正如@nrussell解释的那样,自OS X Mavericks(10.9)以来macOS默认依赖于--stdlib=libc++与传统--stdlib=libstdc++标志进行编译。这可能是我无法复制它的原因,因为一个实现选择稳定而另一个没有。

原始答案

首先,我无法在macOS上复制这个...(见结束)

似乎我们能够在Linux上重现这个(@nrussel)。这意味着在某些时候,链接代码中存在问题。

其次,arma::find_unique使用herematrix ops实施op_find_unique。后者是实现比较器的关键。

因此,简而言之,鉴于您对向量进行排序并且第一项始终被视为唯一,因此无法实现。

测试功能

#include <RcppArmadillo.h>
using namespace Rcpp;
// [[Rcpp::depends(RcppArmadillo)]]

// [[Rcpp::export]]
arma::uvec test(arma::vec& x_) {
    Rcpp::Rcout << "Input:" << x_.t() << std::endl;
    arma::vec x = arma::sort(x_);
    Rcpp::Rcout << "Sorted:" << x.t() << std::endl;
    arma::uvec o = arma::find_unique(x);
    Rcpp::Rcout << "Indices:" << o.t() << std::endl;
    return o;
}

/*** R
set.seed(1991)
(v=sample(1:8,20,TRUE))
## [1] 2 2 1 5 7 6 7 6 4 1 5 3 1 4 4 2 8 7 7 8
sort(v)
## [1] 1 1 1 2 2 2 3 4 4 4 5 5 6 6 7 7 7 7 8 8

test(v)
### Received
##    2.0000   2.0000   1.0000   5.0000   7.0000   6.0000   7.0000   6.0000   4.0000   1.0000   5.0000   3.0000   1.0000   4.0000   4.0000   2.0000   8.0000   7.0000   7.0000   8.0000

### Sorted
## 1.0000   1.0000   1.0000   2.0000   2.0000   2.0000   3.0000   4.0000   4.0000   4.0000   5.0000   5.0000   6.0000   6.0000   7.0000   7.0000   7.0000   7.0000   8.0000   8.0000

### Output
## 0    3    6    7   10   12   14   18
*/