我有一个坐标(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 = ???
还有没有办法在第一次出现时得到这个?
答案 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 我认为相对于此处的其他答案来说,它们都相当慢...