i have a matrix like this: [1 0 0 1 1 1 1 0 1 1 0]
i need to change to: [1 0 0 4 4 4 4 0 2 2 0]
how to make a loop?thanks

댓글 수: 1

Image Analyst
Image Analyst 2013년 1월 6일
Tian, as you can see there are a number of different methods to do that. But I've never done that. It seems like a strange thing to want. Why do you want this output array? What are you going to do with it after you get it? (It's possible you don't really need it, you just think you do.)

댓글을 달려면 로그인하십시오.

 채택된 답변

Azzi Abdelmalek
Azzi Abdelmalek 2013년 1월 6일
편집: Azzi Abdelmalek 2013년 1월 6일

0 개 추천

Improve my previous code speed three times
x=[1 0 0 1 1 1 1 0 1 1 0]
a=find(x);
b=[ 1 diff(a)];
b(b==1)=0;
b(b~=0)=1;
idx=zeros(numel(a),2);
e=1;
c=0;
d=[];
for k=1:numel(a)
e=e+b(k);
c=c*not(b(k))+1;
d(c)=a(k);
idx(e,:)=[d(1) c];
end
for k=1:e
x(idx(k,1):idx(k,1)+idx(k,2)-1)=idx(k,2);
end

댓글 수: 3

Tian Lin
Tian Lin 2013년 1월 14일
Thanks for help! If I have a matrix like this [1 0 0 1 1 0; 0 1 0 1 1 0; ... 0 1 1 0 0 1], that means there are many rows,how to change this:b=[ 1 diff(a)]?
y=[1 0 0 1 1 1 1 0 1 1 0;0 0 0 1 1 0 1 0 1 1 0]
for k1=1:size(y,1)
x=y(k1,:);
a=find(x);
b=[ 1 diff(a)];
b(b==1)=0;
b(b~=0)=1;
idx=zeros(numel(a),2);
e=1;
c=0;
d=[];
for k=1:numel(a)
e=e+b(k);
c=c*not(b(k))+1;
d(c)=a(k);
idx(e,:)=[d(1) c];
end
for k=1:e
x(idx(k,1):idx(k,1)+idx(k,2)-1)=idx(k,2);
end
out(k1,:)=x;
end
Tian Lin
Tian Lin 2013년 1월 15일
Thank you very much

댓글을 달려면 로그인하십시오.

추가 답변 (6개)

Jan
Jan 2013년 1월 6일

1 개 추천

And finally an improved loop method which is about twice as fast as the vectorized method:
function a = RunLength_IgnoZero_loop2(a)
len = length(a);
c = a(1);
ini = 1;
b = zeros(size(a));
for ii = 2:len
if a(ii) ~= c
if c == 0
ini = ii;
else
b(ini) = ii - ini;
b(ii) = ini - ii;
end
c = a(ii);
end
end
if c ~= 0
b(ini) = len - ini + 1;
end
a = cumsum(b);

댓글 수: 4

Jan
Jan 2013년 1월 6일
Some timings:
x = double(rand(1, 1e6) > 0.8);
tic; for ii = 1:100, y = RunLength_IgnoZero(x); end; toc
% Azzi's method without pre-allocation:
21000 seconds (I ran with loop with 1 iteration only)
% Azzi's method with pre-allocation: idx = zeros(numel(a), 2);
241.4 seconds
% RunLength_IgnoZero_loop1:
47.02 seconds
% Jose-Luis' bwconncomp:
25.07 seconds
% RunLength_IgnoZero_Vec:
7.109 seconds
% RunLength_IgnoZero_loop2:
3.687 seconds
Image Analyst
Image Analyst 2013년 1월 6일
My method does not allow more than 65563 separate regions, like the ~160,000 your code produces, so I ran it for 1e5 elements instead. Then I figure we'd just multiply by 10 to compare times. The regionprops() & intlut() takes 0.12 seconds for 1e5 elements, and presumably 1.2 seconds if it were able to process more than 65536 regions.
Jan
Jan 2013년 1월 6일
편집: Jan 2013년 1월 6일
x = double(rand(1, 1e6) > 0.8);
tic; for ii = 1:100, y = FCN(x); end; toc
% RunLength_IgnoZero_loop2:
0.40317 seconds
% Image Analyst's regionprops:
45.40 seconds
(Matlab R2009a/64/Win7/Core2Duo) I assume 0.12 sec means 1 iteration and you are using a modern machine which is 4 times faster than my older processor.
Image Analyst
Image Analyst 2013년 1월 6일
OK, I didn't notice at first that you were doing the same thing 100 times.

댓글을 달려면 로그인하십시오.

Roger Stafford
Roger Stafford 2013년 1월 6일

1 개 추천

Let x be the original row vector of 1's and 0's.
n = length(x);
d = diff([0,x,0]);
f1 = find(d(1:n)>0);
f2 = find(d(2:n+1)<0)+1;
y = zeros(1,n+1);
y([f1,f2]) = [f2-f1,f1-f2];
y = cumsum(y(1:n));
Azzi Abdelmalek
Azzi Abdelmalek 2013년 1월 6일
편집: Azzi Abdelmalek 2013년 1월 6일

0 개 추천

clear
x=[1 0 0 1 1 1 1 0 1 1 0]
e=0,c=0,d=[]
for k=1:numel(x)
if x(k)
e=e+not(c)
c=c+1
d=[d k]
idx(e,:)=[d(1) c]
else
c=0
d=[]
end
end
for k=1:size(idx,1)
x(idx(k,1):idx(k,1)+idx(k,2)-1)=idx(k,2)
end

댓글 수: 1

Jan
Jan 2013년 1월 6일
Pre-allocating idx to the maximum possible size increases the speed.

댓글을 달려면 로그인하십시오.

Image Analyst
Image Analyst 2013년 1월 6일

0 개 추천

Very simple. No loop needed. You just reassign it:
m = [1 0 0 1 1 1 1 0 1 1 0]
% Now make it into what you want:
m = [1 0 0 4 4 4 4 0 2 2 0]
If you have some other algorithm then let's hear it. For example, leave the first element alone but take the next contiguous stretch of 1's and multiply them by 4, and take the next stretch and multiply them by 2. I couldn't figure out what algorithm you were applying, and you didn't say, and didn't say how general you needed this to be (for example can m have values other than 0 and 1, or can it be other lengths, or can it be 2D or 3D?).

댓글 수: 2

Azzi Abdelmalek
Azzi Abdelmalek 2013년 1월 6일
I guess 4 is the number of consecutive 1 in the array, then 2 is the number of consecutive 1, and so on
Image Analyst
Image Analyst 2013년 1월 6일
편집: Image Analyst 2013년 1월 6일
Oh, thanks Azzi, I didn't notice that. In that case, you can use bwlabel, regionprops, and intlut:
m = logical([1 0 0 1 1 1 1 0 1 1 0])
% Group into connected regions.
labeledArray = bwlabel(m)
% Measure the area of all regions.
measurements = regionprops(labeledArray, 'Area');
areas = [measurements.Area]
numberOfAreas = length(areas);
% Assign each connected area with its area.
% Make a look up table to map each region number into the area of that region.
lookUpTable = uint16([0 areas, zeros(1,65536-numberOfAreas-1)]);
% Do the actual mapping.
output = intlut(uint16(labeledArray), lookUpTable)
(Requires the Image Processing Toolbox.) This should also work with 2D arrays.

댓글을 달려면 로그인하십시오.

Jan
Jan 2013년 1월 6일
편집: Jan 2013년 1월 6일

0 개 추천

An inplace method, which changes the input vector on the fly without storing an index list - this muight be an advantage for large data sets:
function a = RunLength_IgnoZero_loop1(a)
len = length(a);
c = a(1);
ini = 1;
for ii = 2:len
if a(ii) ~= c
if c == 0
ini = ii;
else
a(ini:ii-1) = ii - ini;
end
c = a(ii);
end
end
% care about last segement:
if c ~= 0
a(ini:len) = len - ini + 1;
end
Jan
Jan 2013년 1월 6일
편집: Jan 2013년 1월 6일

0 개 추천

For the test data x = double(rand(1, 1e6) > 0.8) this vectorized method is 9 times faster than my loop approach:
function a = RunLength_IgnoZero_Vec(a)
pos = [false, a > 0, false];
start = strfind(pos, [false, true]);
stop = strfind(pos, [true, false]) -1;
run = stop - start + 1;
b = zeros(size(a));
b(start) = run;
b(stop+1) = -run;
if length(b) == length(a)
a = cumsum(b);
else
a = cumsum(b(1:length(b) - 1));
end

카테고리

도움말 센터File Exchange에서 Loops and Conditional Statements에 대해 자세히 알아보기

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!

Translated by