Remove overlapping index ranges within a single array
13 次查看(过去 30 天)
显示 更早的评论
This is similar to a previous question: http://www.mathworks.com/matlabcentral/answers/68336-overlapping-time-intervals-without-for-while-loops
I have set of indices from a larger array in a row-wise manner:
totalMat = ones(15,1); a = [1,2; 3,5; 4,12; 6,11; 8,15];
These are meant to represent indices in a single column array (totalMat) that will be set to some value.
My goal is to determine from a top-down approach which which indices are not overlapping. Eg, the first set of indices (row), which is '1-2', does not overlap with anything, but the second set of indices ('3-5' overlaps with the next one, so the following index would be removed. Having removed the third row, the fourth does not overlap. The final row overlaps with the third, and is removed. The output would be:
b =
1 2
3 5
6 11
Then, ideally, I could set the indices in b to a value - i.e.
totalMat(1:2,3:5,6:11) = 20;
I've done this with while loops and subsequent eval() statements, but I need it to be vectorized to get it done in a reasonable amount of time - my totalMat can be as long as 32 million elements.
I'd like to do away with the eval() if possible. Lastly, this is not a homework question, but from a newbie programmer...
Thanks!
0 个评论
回答(3 个)
Azzi Abdelmalek
2013-7-24
编辑:Azzi Abdelmalek
2013-7-24
Edit
a = [1,2; 3,5; 3,6; 4,5; 8,10]
b=arrayfun(@(x) a(x,1):a(x,2),1:size(a,1),'un',0);
k=1;
while k<numel(b)
c=b(k+1:end);
idx=cellfun(@(x) any(ismember(x,b{k})),c);
if any(idx)
b(logical([ zeros(1,numel(b)-numel(idx)-1) 1 idx]))=[];
else
b(logical([ zeros(1,numel(b)-numel(idx)) idx]))=[];
end
k=k+1;
end
out=cell2mat(cellfun(@(x) [x(1) x(end)],b','un',0))
Azzi Abdelmalek
2013-7-24
a= [1,2;3,5;4,12;5,15;6,23;10,12;13,14;19,22;24,27;26,28];
b=arrayfun(@(x) a(x,1):a(x,2),1:size(a,1),'un',0);
k=1;
while k<numel(b)
c=b(k+1:end);
idx=cellfun(@(x) any(ismember(x,b{k})),c);
b(logical([ zeros(1,numel(b(1:k))) idx]))=[];
k=k+1;
end
out=cell2mat(cellfun(@(x) [x(1) x(end)],b','un',0))
4 个评论
Jan
2013-7-25
@Azzi: This can be simplified:
b(logical([ zeros(1,numel(b(1:k))), idx]))=[];
numel(b(1:k)) equals k. And converting ZEROS to LOGICAL is slower than using FALSE directly:
b([false(1, k), idx]) = [];
Jan
2013-7-26
编辑:Jan
2013-7-26
Some improvements of the loop you've posted as a comment:
totalMat2 = ones(numInd,1);
lenA = size(a, 1);
keeps = true(1, lenA); % as a vector instead of a matrix
currindex = 0;
exceed = a(:, 2) > length(totalMat2);
a(exceed, 2) = length(totalMat2);
for k = 1:lenA % length(a(:,1)) creates a(:,1) explicitly
if a(k,1) <= currindex
keeps(k) = false;
else
currindex = a(k, 2);
totalMat2(a(k,1):a(k,2)) = 20;
end
end
out2 = reshape(a(keeps, :), [], 2); % Automatic size matching
"i" should be avoided as variable to reduce confusions with the imaginary unit.
0 个评论
另请参阅
类别
在 Help Center 和 File Exchange 中查找有关 Logical 的更多信息
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!