Ash
Ash

Reputation: 328

Vectorization- Matlab

Given a vector

X = [1 1 1 1 1 2 2 2 2 2 2 3 3 3 3 3]

I would like to generate a vector such

Y = [1 2 3 4 5 1 2 3 4 5 6 1 2 3 4 5]

So far what I have got is

idx = find(diff(X))
Y   = [1:idx(1) 1:idx(2)-idx(1) 1:length(X)-idx(2)]

But I was wondering if there is a more elegant(robust) solution?

Upvotes: 2

Views: 100

Answers (3)

Luis Mendo
Luis Mendo

Reputation: 112759

Here's another approach:

Y = sum(triu(bsxfun(@eq, X, X.')), 1);

This works as follows:

  1. Compare each element with all others (bsxfun(...)).
  2. Keep only comparisons with current or previous elements (triu(...)).
  3. Count, for each element, how many comparisons are true (sum(..., 1)); that is, how many elements, up to and including the current one, are equal to the current one.

Upvotes: 3

Divakar
Divakar

Reputation: 221684

One approach with diff, find & cumsum for a generic case -

%// Initialize array of 1s with the same size as input array and an 
%// intention of using cumsum on it after placing "appropriate" values
%// at "strategic" places for getting the final output.
out = ones(size(X))

%// Find starting indices of each "group", except the first group, and
%// by group here we mean run of identical numbers.
idx = find(diff(X))+1

%// Place differentiated and subtracted values of indices at starting locations
out(idx) = 1-diff([1 idx])

%// Perform cumulative summation for the final output
Y = cumsum(out)

Sample run -

X =
     1     1     1     1     2     2     3     3     3     3     3     4     4     5
Y =
     1     2     3     4     1     2     1     2     3     4     5     1     2     1

Just for fun, but customary bsxfun based alternative solution -

%// Logical mask with each column of ones for presence of each group elements
mask = bsxfun(@eq,X(:),unique(X(:).'))  %//'

%// Cumulative summation along columns and use masked values for final output
vals = cumsum(mask,1)
Y = vals(mask)

Upvotes: 5

Miki
Miki

Reputation: 16

Another method is using the function unique

like this:

[unqX ind Xout] = unique(X)

Y = [ind(1):ind(2) 1:ind(3)-ind(2) 1:length(X)-ind(3)]

Whether this is more elegant is up to you.


A more robust method will be:

[unqX ind Xout] = unique(X)
for ii = 1:length(unqX)-1
    Y(ind(ii):ind(ii+1)-1) = 1:(ind(ii+1)-ind(ii));
end

Upvotes: 0

Related Questions