1

我正在尝试做的事情

我有一个数字数组:

>> A = [2 2 2 2 1 3 4 4];

我想找到可以找到每个数字的数组索引:

>> B = arrayfun(@(x) {find(A==x)}, 1:4);

换句话说,这B应该告诉我:

>> for ii=1:4, fprintf('Item %d in location %s\n',ii,num2str(B{ii})); end
Item 1 in location 5
Item 2 in location 1  2  3  4
Item 3 in location 6
Item 4 in location 7  8

这就像 的第二个输出参数unique,但不是第一次(或最后一次)出现,我想要所有的出现。我认为这称为反向查找(其中原始键是数组索引),但如果我错了,请纠正我。

我怎样才能更快地做到这一点?

我上面给出的答案是正确的,但它会随着唯一值的数量而急剧增加。对于一个真正的问题(其中A有 1000 万个元素和 10 万个唯一值),即使这个愚蠢的 for 循环也快 100 倍:

>> B = cell(max(A),1);
>> for ii=1:numel(A), B{A(ii)}(end+1)=ii; end

但我觉得这不可能是最好的方法。

我们可以假设A它只包含从 1 到最大值的整数(因为如果它不包含,我总是可以通过它unique来实现它)。

4

2 回答 2

3

这是一个简单的任务accumarray

out = accumarray(A(:),(1:numel(A)).',[],@(x) {x})  %'

out{1} = 5
out{2} = 3 4 2 1
out{3} = 6
out{4} = 8 7  

但是accumarray由于不稳定(在unique's 的意义上),因此您可能想在这里查看 accumarray 的稳定版本,如果这是一个问题。


上面的解决方案还假设A用整数填充,最好在它们之间没有间隙。如果不是这种情况,则无法unique提前调用:

A = [2.1 2.1 2.1 2.1 1.1 3.1 4.1 4.1];

[~,~,subs] = unique(A)
out = accumarray(subs(:),(1:numel(A)).',[],@(x) {x})

总而言之,使用浮点数并返回排序输出的最通用解决方案可能是:

[~,~,subs] = unique(A)
[subs(:,end:-1:1), I] = sortrows(subs(:,end:-1:1));  %// optional
vals = 1:numel(A);                                   
vals = vals(I);                                      %// optional
out = accumarray(subs, vals , [],@(x) {x});

out{1} = 5
out{2} = 1 2 3 4
out{3} = 6
out{4} = 7 8  

基准

function [t] = bench()
    %// data
    a = rand(100);
    b = repmat(a,100);
    A = b(randperm(10000));

    %// functions to compare
    fcns = {
        @() thewaywewalk(A(:).');
        @() cst(A(:).');
    }; 

    % timeit
    t = zeros(2,1);
    for ii = 1:100;
        t = t + cellfun(@timeit, fcns);
    end
    format long
end

function out = thewaywewalk(A) 
    [~,~,subs] = unique(A);
    [subs(:,end:-1:1), I] = sortrows(subs(:,end:-1:1));
    idx = 1:numel(A);
    out = accumarray(subs, idx(I), [],@(x) {x});
end
function out = cst(A) 
    [B, IX] = sort(A);
    out  = mat2cell(IX, 1, diff(find(diff([-Inf,B,Inf])~=0)));
end

0.444075509687511  %// thewaywewalk
0.221888202987325  %// CST-Link

令人惊讶的是,稳定的版本accumarray比不稳定的版本快,因为 Matlab 更喜欢使用排序数组。

于 2016-02-11T19:59:54.593 回答
3

这个解决方案应该在 O(N*log(N)) 中工作,因为排序,但是非常占用内存(需要 3 倍的输入内存量):

[U, X] = sort(A);
    B  = mat2cell(X, 1, diff(find(diff([Inf,U,-Inf])~=0)));

不过我对表演很好奇。

于 2016-02-11T20:19:00.293 回答