dsmalenb
dsmalenb

Reputation: 149

Eliminate Cell Arrays with equal elements

In my main script, I am trying to eliminate cell arrays of S that have the same elements. For example, if you run the current script (with a=v=2) then you will obtain the following values for S:

S{1}(:, :, 1) = [0 0; 0 0]; S{1}(:, :, 2) = [0 0; 0 0];
S{2}(:, :, 1) = [0 0; 1 1]; S{2}(:, :, 2) = [0 1; 0 1];
S{3}(:, :, 1) = [0 1; 0 1]; S{3}(:, :, 2) = [0 0; 1 1];
S{4}(:, :, 1) = [1 0; 1 0]; S{4}(:, :, 2) = [1 1; 0 0];
S{5}(:, :, 1) = [1 1; 0 0]; S{5}(:, :, 2) = [1 0; 1 0];
S{6}(:, :, 1) = [1 1; 1 1]; S{6}(:, :, 2) = [1 1; 1 1];

The code should see S{2} and S{3}, S{4} and S{5} as having the same subsets. Therefore, the results I wish to get should be S{1}, S{2}, S{4}, and S{6}.

I know MATLAB has the ismember, isequal, etc. functions but they do not seem to work on cell arrays...or I could not get them working.

Is there a concise way to handle this with cell arrays as it is currently written?

Main Script:

clear all
clc

a = 2;
v = 2;

R = dec2base(0:1:v^(v^a)-1, v)-'0';
cnt1 = 0;
cnt2 = 0;

for j=1:v^(v^a)
    % List all degenerates in Psi1 
    V =  FN_Break(a, v, R(j,:));
    if V > 0 % Connector is degenerate
        cnt1 = cnt1 + 1;
        Psi1(cnt1,1) = j-1;
        % Store all "breaks" into cell array S
        S{cnt1} = FN_Break_T(a,v,R(j,:));
    else % Connector is not degenerate
        cnt2 = cnt2 + 1;
        Psi2(cnt2,1) = j-1;
    end
end

Function FN_Break:

function [valU] = FN_Beak(a, v, R)

FreeAtomCtr = 0;

for j=0:v^a-1
    for k=1:a
        for l=1:a   
            B =  dec2base(j,v,a);
            atom(l,j+1) = str2num(B(l));
        end
    end
end

for j=1:a % Do this for each atom
    cnt(1:v) = 0;
    for k = 1:v^a  % Do this for each position of each atom
        for l=0:v-1       % Break this down for each value
            if atom(j,k) == l
               cnt(1+l) = cnt(1+l) + 1;
               T(1+l, cnt(1+l),j) = R(k); 
            end
        end
    end
end

for j=1:a
    B = unique(T(:,:,j), 'rows');
    if dot(size(B), [1 0]) < v   % does not depend on this atom
       FreeAtomCtr = FreeAtomCtr + 1;
    end
end

valU = FreeAtomCtr;
end

function FN_Break_T:

function [valU] = FN_Beak_T(a, v, R)

FreeAtomCtr = 0;

for j=0:v^a-1
    for k=1:a
        for l=1:a   
            B =  dec2base(j,v,a);
            atom(l,j+1) = str2num(B(l));
        end
    end
end

for j=1:a % Do this for each atom
    cnt(1:v) = 0;
    for k = 1:v^a  % Do this for each position of each atom
        for l=0:v-1       % Break this down for each value
            if atom(j,k) == l
               cnt(1+l) = cnt(1+l) + 1;
               T(1+l, cnt(1+l),j) = R(k); 
            end
        end
    end
end

for j=1:a
    B = unique(T(:,:,j), 'rows');
    if dot(size(B), [1 0]) < v   % does not depend on this atom
       FreeAtomCtr = FreeAtomCtr + 1;
    end
end

valU = T;
end

Upvotes: 0

Views: 44

Answers (1)

sco1
sco1

Reputation: 12214

One approach could be to hash your combinations and use those to compare the cell contents. You can use ismember to index pairs based on possible combinations (4, in this case), then sort the results and use unique to find the first instance of each unique (sorted) hash.

For example:

S{1}(:, :, 1) = [0 0; 0 0]; S{1}(:, :, 2) = [0 0; 0 0];
S{2}(:, :, 1) = [0 0; 1 1]; S{2}(:, :, 2) = [0 1; 0 1];
S{3}(:, :, 1) = [0 1; 0 1]; S{3}(:, :, 2) = [0 0; 1 1];
S{4}(:, :, 1) = [1 0; 1 0]; S{4}(:, :, 2) = [1 1; 0 0];
S{5}(:, :, 1) = [1 1; 0 0]; S{5}(:, :, 2) = [1 0; 1 0];
S{6}(:, :, 1) = [1 1; 1 1]; S{6}(:, :, 2) = [1 1; 1 1];

combinations = [0 0; 0 1; 1 0; 1 1];
% Assume array in every cell has the same shape
hash = zeros(size(S{1}, 1)*size(S{1}, 3), numel(S));
for ii = 1:numel(S)
    [~, hash(:,ii)] = ismember([S{ii}(:, :)].', combinations, 'rows');
end

hash = sort(hash, 1).';
[~, keepidx] = unique(hash, 'rows');
S = S(keepidx);

Which gives the desired S (cells 1, 2, 4, 6)


If you instead want to nest the duplicates, you can use the following:

hash = sort(hash, 1).';
[~, keepidx, uniqueidx] = unique(hash, 'rows');
bincounts = accumarray(uniqueidx, 1);  % Count occurrences

for ii = 1:numel(bincounts)
    if bincounts(ii) > 1
        idx = find(uniqueidx == ii);
        S{idx(1)} = S(idx);  % Nest duplicates in first instance of duplicate
    end
end
S = S(keepidx);

This uses the third output of unique along with accumarray to obtain the occurrence count of each unique combination. The duplicates are nested and then the original cell array is pruned as before.

Upvotes: 1

Related Questions