How to separate vector into vectors of different lengths

I have a vector y=[1:1:10] and length vector l=[2,5,10] % these are the sample number of the vector y; I want to separate the y vector so that y1=[1,2]; y2=[3,4,5]; y3=[6,7,8,9,10];

4 Comments

"I want to separate the y vector so that y1 ... y2 ... y3 ..."
Do NOT do that. Dynamically accessing variables names is one way that beginners force themselves into writing slow, complex, buggy code. Read this to know why:
You should store the data in one array (e.g. a cell array) and use indexing.
Uh ... facepalm
Thank you Star Strider. If I had looked I would have saved myself reinventing the wheel :)
My pleasure, Stephen. I posted my Answer 6 days (and 1115 Questions) before this one, so it would have been difficult to find.
I probably should have made my explanation a bit more obvious, and emphasized that ‘Out’ was the desired result, although I thought it would be self-explanatory as I posted it.
Live and learn!

Sign in to comment.

 Accepted Answer

y=[1:1:10] ;
l=[2,5,10] ;
y1=[1,2] ;
y2=[3,4,5] ;
y3=[6,7,8,9,10] ;
iwant = cell(length(l),1) ;
iwant{1} = y(1:l(1)) ;
for i = 2:length(l)
iwant{i} = y(l(i-1)+1:l(i)) ;
end

1 Comment

This works fine. But facing an issue with the actual data when I have a situation of similar to l=[2,5,9] here I would like to collect data in between the lengths 2to5; 5to9; and 9to10

Sign in to comment.

More Answers (1)

The simple MATLAB way:
>> y = 1:10;
>> x = [2,5,10];
>> c = mat2cell(y,1,diff([0,x]));
>> c{:}
ans =
1 2
ans =
3 4 5
ans =
6 7 8 9 10

13 Comments

+1 @Stephen expert in cell
Using this code with my actual data produce error: Error using horzcat Dimensions of matrices being concatenated are not consistent.
Error in separate_impacts (line 64) cc = mat2cell(y_mean,1,diff([0,idx]));
Actual data has a vector y_mean of size 2124288*1; and idx=[297121,432478,491657,656944,962731,1129612,1314841,1577916,1767257,1925084]
similar to the situation when : when I have a situation of similar to l=[2,5,9] here I would like to collect data in between the lengths 2to5; 5to9; and 9to10
@Md Shahriar Islam: of course you get an error, because your actual data is in a column vector, whereas what you showed us in your question is a row vector. But this is easy to fix, just swap the dimensions in the mat2cell call:
cc = mat2cell(y_mean(:),diff([0,idx]),1);
Because I added the (:) to the first input, this will work with vectors of any orientation.
It is still not working. I think it is because the dimension in idx are not same with the dimension of y_mean. Check y_mean , it has 2124288 samples. On the other hand the last value in idx is 1925084. So when we are using diff here its taking 0to1925084 samples which is not same to the sample number of y_mean 2124288
@Md Shahriar Islam: then you will have to add the last index yourself:
dd = diff([0,idx,numel(y_mean)]);
cc = mat2cell(y_mean(:),dd,1);
actually,used this previously. didnt work. still not working
"actually,used this previously. didnt work. still not working"
It works perfectly for me:
>> y = rand(2124288,1); % fake data
>> idx = [297121,432478,491657,656944,962731,1129612,1314841,1577916,1767257,1925084];
>> dd = diff([0,idx,numel(y)]);
>> cc = mat2cell(y(:),dd,1);
And checking the size of the vector in each cell:
>> num = cellfun(@numel,cc)
num =
297121
135357
59179
165287
305787
166881
185229
263075
189341
157827
199204
>> sum(num)
ans = 2124288
So obviously your code is buggy. But as you have not shown us any of the code you are trying, we have no way to know what mistakes you made in your code or your explanation. If you want help, please write more than just "didnt work. still not working", which tells us nothing useful and gives us no way to actually help you.
Yes; Maybe my code is buggy; I am sharing here my code.
clc
clear
fname='4CH000M.wav';
thresh_relative=10;%set threshold relative to std
t_min=1;%(s) minimum time between impacts
[y_raw,Fs]=audioread(fname);
y_mean=mean(y_raw,2);%average both channels for some noise reduction
y_thresh=thresh_relative*std(y_mean);
idx=find(abs(y_mean)>y_thresh);
k_min=t_min*Fs;%minimum number of samples between impacts
k=1;
while k<numel(idx)
%remove any peaks for k_min samples after impact
idx((idx>idx(k))&(idx<(idx(k)+k_min)))=[];
k=k+1;
end
t=(0:(numel(y_mean)-1))/Fs;
figure(1)
plot(t,y_mean)
hold all
plot(xlim,y_thresh*[1 1],'k--')
plot(xlim,-y_thresh*[1 1],'k--')
plot(t(idx),y_mean(idx),'ro')
hold off
yy=y_mean;
xx = idx;
dd = diff([0,xx,numel(yy)]);
cc = mat2cell(yy(:),dd,1);
num = cellfun(@numel,cc)
@Md Shahriar Islam: when I run your code the only error is due to xx being a column vector (again this is unlike your question, where it is a row vector). This is also trivial to fix:
dd = diff([0;xx(:);numel(yy)]);
Giving code that runs without any error:
>> dd = diff([0;xx(:);numel(yy)]);
>> cc = mat2cell(yy(:),dd,1);
>> num = cellfun(@numel,cc)
num =
445672
119018
134472
107560
102999
127632
265177
128830
115453
191299
>> sum(num)
ans =
1738112
But I suspect that your entire algorithm is fundamentally flawed: If you are trying to detect the moment of "impact", then simply removing a fixed number of trailing idx elements might not work. Consider this example:
ind = [ 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 0, 1, 1] % abs(..)>thresh
tvec = [ 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15,16]
idx = ???
Lets assume that t_min is 6: what are the indices that you would expect to have in the output idx ?:
  1. idx=[3,9,15] 6-second steps, any 1 in a group allowed.
  2. idx=[3,15] Only the first 1 in each group is permitted.
  3. idx=[???] Something else? Please explain what and why.
In my algorithm I have a line:
idx=find(abs(y_mean)>y_thresh);
This will basically extract a lot of idx (2331 size actually)
Now as I am only separating all the impacts from one audio file. I have used some assumed threshold value to compare the y_mean and based on that comparison idx are extracted. next the while command actually separates the impacts by removing extra idx value in between a length k_min which is also assumed value initially.
For your answer, the answer for 3.idx[both 1. and 2.] based on another logic whichever applies.
I am not saying my algorithm is not flawed. This is how I was able to separate impacts. The smaller impacts less than the threshold value are more likely the reverberation.
You are more than welcome to propose any other algorithm to separate the impacts from this audio file. I will be glad to learn the right way. Thank you very much.
@Md Shahriar Islam: You missed my point. The question is: do you want the values in idx to represent the first 1 in a sequence of 1's, or do you want to detect any 1 in a sequence of 1's?
The same question in different words: what are the indices in idx supposed to represent? Are they supposed to represent the start of each "impact".
Please read my previous comment again, and tell my what indices you would expect for the small example I gave. This is very important to know exactly what you mean when you say that you want "to separate impacts".
@Stephen Cobeldick: sorry, missed your point.
Yes. I want values in idx to represent 1 in a sequence of 1's.
idx=[3,8,15]

Sign in to comment.

Community Treasure Hunt

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

Start Hunting!