使用MATLAB在坐标列表中找到每个坐标的第一个和最后一个索引

时间:2019-02-27 15:27:57

标签: arrays matlab unique

我有一个坐标(x,y)的列表,我需要在列表中找到每个坐标的第一个和最后一个出现的索引。 示例(在我的使用广播中,我有〜3000万个坐标):

x = [1 3 7 1 3];
y = [5 1 6 5 1];
first = [1 2 3 1 2];
last  = [4 5 3 4 5];

我使用矩阵和循环来实现它,看起来像这样,但是很慢:

x1 = min(x);
y1 = min(y);
x2 = max(x);
y2 = max(y);
tic
Mlast = zeros(y2-y1+1, x2-x1+1);
Mfirst = Mlast;

ind = sub2ind(size(Mlast),y-y1+1, x-x1+1);

for i1=1:length(ind)
    first = Mfirst(ind(i1));

    if first == 0
        first = i1;
    end

    Mlast(ind(i1)) = i1;
    Mfirst(ind(i1)) = first;
end

我试图对整个过程进行矢量化处理,但是我只成功使用了Mlast:

ind = sub2ind(size(Mlast),y-y1+1, x-x1+1);
t = (1:length(x))';
Mlast(ind) = t;
Mfirst = ???

还有没有办法在第一次出现时得到这个?

3 个答案:

答案 0 :(得分:5)

unique函数可以做到:

[~, b, c] = unique([x(:) y(:)], 'rows', 'first');
first = b(c).';
[~, b, c] = unique([x(:) y(:)], 'rows', 'last');
last = b(c).';

答案 1 :(得分:2)

假设坐标是正整数,特别是当坐标范围较小时,可以使用accumarray

x1 = min(x);
y1 = min(y);
x2 = max(x);
y2 = max(y);
sz = [y2-y1+1, x2-x1+1];
ind = sub2ind(sz,y-y1+1, x-x1+1);

ifirst = accumarray(ind(:), 1:numel(ind), [], @min);
ilast  = accumarray(ind(:), 1:numel(ind), [], @max);
Mfirst = ifirst(ind);
Mlast  = ilast(ind);

对于更大的范围,您可以使用稀疏选项:

ifirst = accumarray(ind(:), 1:numel(ind), [], @min,[],1);
ilast  = accumarray(ind(:), 1:numel(ind), [], @max,[],1);

答案 2 :(得分:1)

如果您有3000万点,则可能没有足够的内存用于此方法...但是对于较小的数组,这是相当快的

x = [1 3 7 1 3];
y = [5 1 6 5 1];

xy = cat( 3, x, y );

chk = all( xy == permute( xy, [2 1 3] ), 3 );

[~,first] = max( chk );
[~,last] = max( flipud( chk ) );
last = size(chk,1) - last + 1;

编辑,您也可以使用findgroups进行此操作,并遍历唯一坐标而不是每个坐标,以使循环可能更短...

x = [1 3 7 1 3];
y = [5 1 6 5 1];

g = findgroups( x, y );   
first = zeros( size( x ) );
last = first;
for ii = 1:max(g)
    idx = (ii==g);
    first( idx ) = find( idx, 1, 'first' );
    last( idx ) = find( idx, 1, 'last' );
end 

Edit2 我认为相对于此处的其他答案来说,它们都相当慢...