Pergunta

I have a vector that contains repeated numbers like so:

[1 1 1 1 5 5 5 5 93 93 93 6 6 6 6 6 6] and so on. What I want to do is to group the similar values (1's, 5's, etc.). I would like to have each of the unique values in a row of a big matrix, like:

[ 1  1  1  1  0  0

  5  5  5  5  0  0

 93 93 93  0  0  0

  6  6  6  6  6  6]

I don't know the maximum number of occurrence of a unique value, so it is ok to create an initial zero matrix with a large number of columns (that I am sure is bigger than the maximum number of occurrence of a unique value). Any help is highly appreciated.

Foi útil?

Solução

How about this?

A = [1 1 1 1 5 5 5 5 93 93 93 6 6 6 6 6 6];
[a,b] = hist(A,unique(A))

f = @(x) [ones(1,a(x)) zeros(1,max(a)-a(x))]

X = cell2mat( arrayfun(@(x) {f(x)*b(x)}, 1:numel(b) )' )

returns:

X =

     1     1     1     1     0     0
     5     5     5     5     0     0
     6     6     6     6     6     6
    93    93    93     0     0     0

I know the order is different, is that important? Otherwise:

n = hist(A,1:max(A))           % counts how often every number apperas
[a b] = unique(A,'stable')     % gets all unique numbers
n = n(a)                       % correlates count and numbers

f = @(x) [ones(1,n(x)) zeros(1,max(n)-n(x))]     % creates the logical index 
                                                 % vector for every single row

X = cell2mat( arrayfun(@(x) {f(x)*b(x)}, 1:numel(b) )' )  %fills the rows

or inspired by Luis Mendo's Answer a little shorter:

n = hist(A,1:max(A));
a = unique(A,'stable')
n = n(a)
Y = repmat(a',1,max(n)).*bsxfun(@le, cumsum(ones(max(n),numel(n))), n)'

returns:

X =

     1     1     1     1     0     0
     5     5     5     5     0     0
    93    93    93     0     0     0
     6     6     6     6     6     6

For the bored people out there, there is a one-line solution:

X = getfield(cell2mat(arrayfun(@(x,y) padarray( padarray(x,[0 y],'replicate','pre'),[0 max(hist(A,1:max(A)))-y],'post'),1:max(A),hist(A,1:max(A)),'uni',0)'),{unique(A,'stable'),2:1+max(hist(A,1:max(A)))})

Or an almost lovely two-liner:

n = hist(A,1:max(A))
X = getfield(cell2mat(arrayfun(@(x,y) padarray( padarray(x,[0 y],'replicate',...
    'pre'),[0 max(n)-y],'post'),1:max(A),n,'uni',0)'),...
    {unique(A,'stable'),2:1+max(n)})

just for fun ;)

Outras dicas

Vectorized solution (no loops):

x = [1 1 1 1 5 5 5 5 93 93 93 6 6 6 6 6 6]; %// data
ind = [find(diff(x)) numel(x)]; %// end of each run of equal values
values = x(ind); %// unique values (maintaining order)
count = diff([0 ind]); %// count of each value
result = bsxfun(@le, meshgrid(1:max(count),1:numel(values)), count.'); %'// mask
result = bsxfun(@times, result, values.'); %'// fill with the values

EDIT:

Alternative procedure that avoids the second bsxfun:

x = [1 1 1 1 5 5 5 5 93 93 93 6 6 6 6 6 6]; %// data
ind = [find(diff(x)) numel(x)];
values = x(ind); %// unique values (maintaining order)
count = diff([0 ind]); %// count of each value
mask = bsxfun(@le, ndgrid(1:max(count),1:numel(values)), count);
result = zeros(size(mask)); %// pre-allocate and pre-shape (transposed) result
result(mask) = x; %// fill in values
result = result.';

This could be one approach -

%%// Input
array1 = [1 1 1 1 5 5 5 5 93 93 93 6 6 6 6 6 6];

%// Main Processing
id = unique(array1,'stable'); %//Find the unique numbers/IDs
mat1 = zeros(numel(id),nnz(array1==mode(array1))); %%// Create a matrix to hold the final result
for k=1:numel(id)
    extent_each_id = nnz(array1==id(k)); %%// Count of no. of occurances for each ID
    mat1(k,1:extent_each_id)=id(k); %%//  Starting from the left to the extent for each ID store that ID
end

Gives -

mat1 =
     1     1     1     1     0     0
     5     5     5     5     0     0
    93    93    93     0     0     0
     6     6     6     6     6     6
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top