MATLAB中的稳定acumarray

MATLAB中的稳定acumarray,matlab,accumarray,stable-sort,Matlab,Accumarray,Stable Sort,MATLAB的内置函数接受函数fun作为第四个参数 A = accumarray(subs,val,sz,fun); 这将fun应用于val中的每个元素子集,这些元素在subs中具有相同的下标。然而,文件指出: 如果subs中的下标未根据其线性索引进行排序,fun不应取决于其输入数据中值的顺序 我们如何实现一个稳定版本的accumarray,它没有这个限制,但可以保证子集采用与val相同的顺序 示例: subs = [1:10,1:10]; val = 1:20; accumarray(sub

MATLAB的内置函数接受函数
fun
作为第四个参数

A = accumarray(subs,val,sz,fun);
这将
fun
应用于
val
中的每个元素子集,这些元素在
subs
中具有相同的下标。然而,文件指出:

如果
subs
中的下标未根据其线性索引进行排序,
fun
不应取决于其输入数据中值的顺序

我们如何实现一个稳定版本的
accumarray
,它没有这个限制,但可以保证子集采用与
val
相同的顺序

示例:

subs = [1:10,1:10];
val = 1:20;
accumarray(subs(:), val(:), [], @(x)x(end)).'
如果
accumarray
稳定,则预期输出为
11:20
。事实上,结果是:

ans =
    11    12    13    14     5     6     7    18    19    20
我们的实施应产生:

accumarrayStable(subs(:), val(:), [], @(x)x(end)).'`
ans =
    11    12    13    14    15    16    17    18    19    20

我们可以使用
sortrows
作为预处理步骤,首先对索引和相应的值进行排序,正如其文档所述:

SORTROWS
使用了稳定版的快速排序

由于
subs
中的下标应该根据它们的线性索引进行排序,因此我们需要按照相反的字典顺序对它们进行排序。这可以通过在使用
sortrows
之前和之后翻转列顺序来实现

这为我们提供了稳定版本的
accumarray
的以下代码:

function A = accumarrayStable(subs, val, varargin)
[subs(:,end:-1:1), I] = sortrows(subs(:,end:-1:1));
A = accumarray(subs, val(I), varargin{:});
备选方案:

subs = [1:10,1:10];
val = 1:20;
accumarray(subs(:), val(:), [], @(x)x(end)).'
正如Luis Mendo所建议的,除了
sortrows
,还可以从下标生成线性索引,并使用
sort

function A = accumarrayStable(subs, val, varargin)
if numel(varargin)>0 && ~isempty(varargin{1})
    sz = varargin{1};
else
    sz = max(subs,[],1);
end
[~, I] = sort(subs*cumprod([1,sz(1:end-1)]).');
A = accumarray(subs(I,:), val(I), sz, varargin{:});
注意,我们应该使用
1+(subs-1)*cumprod([1,sz(1:end-1)])。
转换为线性指数。我们省略了
+1
-1
,因为
排序的结果仍然相同;这为我们节省了一些周期

以上哪一种解决方案更快将取决于您的机器和MATLAB版本。例如,您可以通过以下方式进行测试:

A = randi(10, 1e4, 5); 
timeit(@()accumarrayStable(A(:,1:end-1), A(:,end), [], @(x)x(1))

我打算建议
sortrows
关于(它也在中使用)。好的问答@路易斯门多:我想有人可能需要这个,所以为什么不改变一下回答我自己的问题呢?:-)需要在馈送到
sortrows
之前反转索引,以便在线性索引意义上完成排序,对吗?也许你可以把它添加到你的answer@LuisMendo:我将添加第二个版本。这似乎与我使用
fun=@(x)x(end)
进行测试有关,无论出于何种原因,这会使版本2比版本1慢很多。。。我们可能应该使用一个测试用例,其中
fun~=sum
,否则稳定的东西就没有任何意义了。现在我看到了你关于不使用
sum
错误:-)的评论,所以我们同意稳定性对于“非标准”函数是有意义的