3
votes

In trying to port an algorithm from C# to Matlab I found that Matlab is inefficient at running for loops. As such I want to vectorize the algorithm.

I have following inputs:

lowrange:

[ 00 10 20 30 40 50 ... ]

highrange:

[ 10 20 30 40 50 60 ... ]

These arrays are equal in length.

I now have a third array Values (which could be any length) and for this array I want to count the occurrences of Values elements between lowerange(i) and highrange(i) (You can see I'm coming from a for loop).

The output should be an array of length lowrange/highrange.

So with the above arrays and input LineData:

[ 1 2 3 4 6 11 12 16 31 34 45 ]

I expect to get:

[ 05 03 00 02 01 00 ...  ]

I tried the (for me) obvious thing:

LineData(LineData < PixelEnd & LineData > PixelStart) 

But that doesn't work because it just checks LineData on an element by element way. It does not try to apply the comparison over all values in LineData.

Unfortunately, I cannot come up with anything else since I'm not yet used to think in a Matlab 'vector' way, let alone knowing all applicable instructions from memory.

2
What if any element from Values falls on the boundary like 10 or 20? Also, are the intervals between elements of lowrange and highrange the same, which is 10 in the given data. - Divakar
@Divakar good points... My data is generated by a physical process so it might occur that something falls exactly on the boundary. However, I assume that hits suggested in one of the answers would have provisions for such an event (but indeed, I would need to check what they are). On the other hand, yes the interval would always be constant. - Kris

2 Answers

5
votes

As you are looking to do a basic histogram with given edges, you can use Matlabs built-in function histc:

values = [ 1 2 3 4 6 11 12 16 31 34 45 ];
edges = 0:10:60;
histc(values, edges)

ans =

 5     3     0     2     1     0     0
2
votes

For ranges with identical intervals and starting from 0, here's a bsxfun based counting approach -

LineData = [ 1 2 3 4 6 11 12 16 31 34 45 ] %// Input

interval = 10; %// interval width
num_itervals = 6; %// number of intervals

%// Get matches for each interval and sum them within each interval for the counts
out = sum(bsxfun(@eq,ceil(LineData(:)/interval),1:num_itervals)) 

Output -

LineData =
     1     2     3     4     6    11    12    16    31    34    45
out =
     5     3     0     2     1     0

Assuming that the last interval would be the one holding the max of input data, you can try out a diff + indexing based approach too -

LineData = [ 1 2 3 4 6 11 12 16 31 34 45 ] %// Input
interval = 10; %// interval width

labels = ceil(LineData(:)/interval); %// set labels to each input entry
df_labels = diff(labels)~=0; %// mark the change of labels
df_labels_pos = find([df_labels; 1]); %// get the positions of label change
intv_pos= labels([true;df_labels]);%// position of each interval with nonzero counts

%// get counts from interval between label position change and put at right places
out(intv_pos) =  [ df_labels_pos(1) ; diff(df_labels_pos)];