0

I have two vectors representing the edges and levels some continuous data (this is simulated at the moment).

edges = [50, 120, 170, 200, 220, 224, 250]
levels = [24,3,30,0,36,0]

How would I create a vector that has 24 for the first 50 entries, 3 for the subsequent 120 etc?

I've tried

psd = zeros(1,250)
psd(edges) = levels

but this just puts a single value at the relevant position - it's not quite what I want.

Tom Kealy
  • 2,537
  • 2
  • 27
  • 45
  • 2
    `edges` and `levels` are not the same size. Don't you forgot a `0` somewhere? Also your question is not very clear: what is the length of `psd`? Considering your try, it will be 250; but you mention _3 for the subsequent 120_, so I understand that the length of `psd` would be 50+120+...+250 instead. Could you please precise which possibility you have in mind? – Bentoy13 Aug 19 '13 at 16:23

5 Answers5

1

Your description and code don't quite match. Do you want psd to have 250 elements or 1234 (sum(edges), as your use of subsequent would imply)? If it's the latter, you can simply modify edges = cumsum(edges). Secondly, you don't have enough levels for the given edges.

Here's a solution without the use of loops.

edges = [50, 120, 170, 200, 220, 224, 250];
levels = [24,3,30,0,36,0,nan]; % padded with nan for equal length
idxs = length(levels) - sum(bsxfun(@(x,y) x < y,1:max(edges),edges'+1))+1;
pds = levels(idxs)

Or even simpler:

idxs = zeros(1,max(edges));
idxs(edges(1:end-1)+1) = 1;
psd = levels(cumsum(idxs)+1)
mbauman
  • 30,958
  • 4
  • 88
  • 123
1

Here is a little solution, if edges is really the edges of your intervals:

Expand the vector levels with 0 as a first element:

levels = [0, 24, 3, 30, 0, 36, 0];

Then you can do the following:

psd = zeros(1,250);
psd(edges(2:end)-1) = diff(levels);
psd = cumsum(psd);

You put at the interval limits the offset betwwen two consecutive values, 0 elsewhere. When summing up, you have what you expect.

Bentoy13
  • 4,886
  • 1
  • 20
  • 33
0

Involves a loop but it should be OK. Also, your edges and levels need to be of equal length.

v = [];
for i = 1:numel(edges)
    v = [v;level(i)*ones(edges(i),1)];
end

Here's a more efficient version which takes care of the allocation overhead.

v = zeros(sum(edges),1);
c = [0 cumsum(edges)];
for i = 1:numel(edges)-1
    v( c(i)+1:c(i+1) ) = levels(i)*ones(edges(i),1);
end

Just remember ; loops aren't always evil in today's MATLAB. Sometimes, it's the simplest (and clearest) solution.

Jacob
  • 34,255
  • 14
  • 110
  • 165
0

You can use this run-length decoding utility FEX rude(), which implements the approach showed by Bentoy13:

% example inputs
edges  = [2, 3, 1];
levels = [24,3,30];

the result

rude(edges, levels)
ans =
    24    24     3     3     3    30
Community
  • 1
  • 1
Oleg
  • 10,406
  • 3
  • 29
  • 57
0

Inspired by an answer by gnovice you can use this:

psd = levels(cumsum(sparse(1,cumsum([1 edges(1:end-1)]),1,1,sum(edges))));

To make it easier you can create an anonymous function and resuse it instead:

populate = @(L,E) L(cumsum(sparse(1,cumsum([1 E(1:end-1)]),1,1,sum(E))));
psd = popultae(levels, edges);
Community
  • 1
  • 1
Mohsen Nosratinia
  • 9,844
  • 1
  • 27
  • 52