# How to group rows of data into a cell of a cell array?

47 views (last 30 days)
John Hunt on 17 Oct 2017
Commented: Walter Roberson on 12 Mar 2022
I have a data that has xyz information as well as three numbers that group each point together. As an example a row might have [ -1 2 -4 1 2 15] So that atom is at point (-1,2,-4) and it is defined by 1,2,and 15. There is an unknown amount of atoms that have different locations but have the same defined numbers. I want to group all of the atoms that have the same 3 defining numbers in a matrix that is in a cell array (or into structure if that is easier) QN. I have the following code but I am not adding more data to one cell. This is what I have
j=1;
for k = 1:(length(TypesQN)-1)
for p = 1:(length(locQN)-1)
if TypesQN(k,1:4)==locQN(p,4:7)
qn=locQN(p,:);
QN{j}=qn;
j=j+1;
end
end
end
Where the amount of defined numbers is know (TypesQN) and the total dataset length is known (locQN).

Cedric Wannaz on 17 Oct 2017
Edited: Cedric Wannaz on 17 Oct 2017
Here is one way. We start by building a fake data set:
>> A = [rand(10,3), randi(2,10,3)]
A =
0.7513 0.8407 0.3517 1.0000 1.0000 1.0000
0.2551 0.2543 0.8308 1.0000 2.0000 1.0000
0.5060 0.8143 0.5853 2.0000 1.0000 1.0000
0.6991 0.2435 0.5497 2.0000 2.0000 2.0000
0.8909 0.9293 0.9172 2.0000 1.0000 1.0000
0.9593 0.3500 0.2858 1.0000 2.0000 2.0000
0.5472 0.1966 0.7572 2.0000 1.0000 2.0000
0.1386 0.2511 0.7537 1.0000 2.0000 2.0000
0.1493 0.6160 0.3804 1.0000 2.0000 1.0000
0.2575 0.4733 0.5678 1.0000 2.0000 1.0000
Then we find group IDs per unique combination of 3 "ID" numbers:
>> [~,~,gId] = unique( A(:,4:end), 'rows' )
gId =
1
2
4
6
4
3
5
3
2
2
and we use these to split the array:
>> groups = splitapply( @(x){x}, A, gId )
groups =
6×1 cell array
{1×6 double}
{3×6 double}
{2×6 double}
{2×6 double}
{1×6 double}
{1×6 double}
where you can see that the 3 numbers are the same for e.g. group 2:
>> groups{2}
ans =
0.2551 0.2543 0.8308 1.0000 2.0000 1.0000
0.1493 0.6160 0.3804 1.0000 2.0000 1.0000
0.2575 0.4733 0.5678 1.0000 2.0000 1.0000
Note that if you don't want to save the ID numbers in the groups, you can split as follows:
>> groups = splitapply( @(x){x(:,1:3)}, A, gId )
groups =
6×1 cell array
{1×3 double}
{3×3 double}
{2×3 double}
{2×3 double}
{1×3 double}
{1×3 double}
>> groups{2}
ans =
0.2551 0.2543 0.8308
0.1493 0.6160 0.3804
0.2575 0.4733 0.5678
Walter Roberson on 12 Mar 2022
splitapply can be used for cell arrays as well, and it is not limited to doing arithmetic computations on the fields. For example, the following gets the T.Gender fields and for each one takes length() [which would happen to be consistent for each gender]
What datatype do you need to work with? What non-numeric fields do you need to apply functions to?
T = table(Gender,Height);
[G,gender] = findgroups(T.Gender);
splitapply(@(x) {x{1}, cellfun(@length,x.')}, T.Gender, G)
ans = 2×2 cell array
{'Female'} {[6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6]} {'Male' } {[ 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4]}

### More Answers (1)

Walter Roberson on 17 Oct 2017
TypesQN = [randi([-5 5],1000,3), randi(5,1000,3)]; %sample data for testing
[~, ~, group_number] = unique(TypesQN(:,4:6), 'rows');
grouped_atoms = splitapply(@(M) {M}, TypesQN, group_number);
The above requires R2015b or later; if you have an earlier version then the splitapply can be rewritten to other code.