Why accessing to table is slower than accessing to struct?

5 views (last 30 days)
Hi all,
I have a very large dataset of table data type with nested struct. I have carried out two scrips, one which deals with the table and the other with struct by converting the table into a struct (with the table2struct function). However, it seems that dealing with struct is much faster than dealing with the table. Below you will find a sample of my code. For most of the lines, there is no real difference between the two scripts, with the exception of the following that is inside a for-loop and therefore it significantly impacts on the overall script performance. Why such big difference? Is there a way to make it faster?
Sigs{iSig2Load(j)}(Pos2Paste)=single(messageStruct(i).Signals.(Sig{iSig(j)}));
Thank you,
Best regards.
SigNames={'s1','s2','s3','s4','s5'; 'a1','a1','a1','a2','a2'};
MessLength=40;
for i=1:2:MessLength
messageStruct(i).Name='a1';
messageStruct(i).Signals.s1=1;
messageStruct(i).Signals.s2=2;
messageStruct(i).Signals.s3=3;
end
for i=2:2:MessLength
messageStruct(i).Name='a2';
messageStruct(i).Signals.s4=4;
messageStruct(i).Signals.s5=5;
end
tic
UniqueMessFound=unique({messageStruct.Name});
UniqueMessageCount=countcats(categorical({messageStruct.Name},UniqueMessFound));
for iSig=1:length(SigNames(1,:))
Sigs{iSig}=NaN(UniqueMessageCount(strcmp(UniqueMessFound,SigNames{2,iSig})),1);
end
for i=1:MessLength
Sig=fieldnames(messageStruct(i).Signals);
[~,iSig2Load , iSig]=intersect(SigNames(1,:),Sig);
Sig2Sel=SigNames(1,iSig2Load);
for j=1:length(Sig2Sel)
Pos2Paste=find(isnan(Sigs{iSig2Load(j)}),1);
Sigs{iSig2Load(j)}(Pos2Paste)=single(messageStruct(i).Signals.(Sig{iSig(j)}));
end
end
toc
%%
SigNames={'s1','s2','s3','s4','s5'; 'a1','a1','a1','a2','a2'};
MessLength=40;
for i=1:2:MessLength
messageStruct(i).Name='a1';
messageStruct(i).Signals.s1=1;
messageStruct(i).Signals.s2=2;
messageStruct(i).Signals.s3=3;
end
for i=2:2:MessLength
messageStruct(i).Name='a2';
messageStruct(i).Signals.s4=4;
messageStruct(i).Signals.s5=5;
end
tic
message=struct2table(messageStruct);
UniqueMessFound=unique(message.Name);
UniqueMessageCount=countcats(categorical(message.Name,UniqueMessFound));
for iSig=1:length(SigNames(1,:))
Sigs{iSig}=NaN(UniqueMessageCount(strcmp(UniqueMessFound,SigNames{2,iSig})),1);
end
for i=1:MessLength
Sig=fieldnames(message.Signals{i});
[~,iSig2Load , iSig]=intersect(SigNames(1,:),Sig);
Sig2Sel=SigNames(1,iSig2Load);
for j=1:length(Sig2Sel)
Pos2Paste=find(isnan(Sigs{iSig2Load(j)}),1);
Sigs{iSig2Load(j)}(Pos2Paste)=single(message.Signals{i}.(Sig{iSig(j)}));
end
end
toc

Answers (1)

Maadhav Akula
Maadhav Akula on 24 Oct 2019
So, I could see in your code that for the second time measurement you also included the line
message=struct2table(messageStruct);
for time measurement(tic -toc), which takes up a significant chunk of time to compute!
Even then, if you remove that line from time measurement(tic -toc), struct runs significantly faster than the table and this is expected behavior in your case as you are accessing each element of the table in a loop and accessing it is a little slow. But, accessing a variable in a table is not always slow. Accessing a "large enough" subset of rows of a variable is fast. But at some point if the subsets are small and computations surrounding them are very cheap, the table subscripting is going to dominate the time and it will look that table is slower.
So, I would suggest you convert the data into a struct(table2struct) and perform your operation and then convert the data back into table(struct2table).
Hope this helps!
  1 Comment
Serbring
Serbring on 24 Oct 2019
Thank you for your answer.
As far as I understood, the problem is that I am accessing to table element by element and the table is large (more than 2 millions of row). So the best would be looping through names and signals. So, I have developed the following code:
clear all
SigNames={'s1','s2','s3','s4','s5'; 'a1','a1','a1','a2','a2'}';
MessLength=40;
for i=1:2:MessLength
messageStruct(i).Name='a1';
messageStruct(i).Signals.s1=1;
messageStruct(i).Signals.s2=2;
messageStruct(i).Signals.s3=3;
end
for i=2:2:MessLength
messageStruct(i).Name='a2';
messageStruct(i).Signals.s4=4;
messageStruct(i).Signals.s5=5;
end
Pos2Paste=zeros(length(SigNames),1);
tic
message=struct2table(messageStruct);
UniqueMessFound=unique(message.Name);
UniqueMessageCount=countcats(categorical(message.Name,UniqueMessFound));
for iSig=1:length(SigNames(1,:))
Sigs{iSig}=NaN(UniqueMessageCount(strcmp(UniqueMessFound,SigNames{2,iSig})),1);
end
for i=1:length(SigNames(:,1))
imes=find(contains({messageStruct.Name},SigNames(i,2)));
sig2Search=find(contains(SigNames(:,2),SigNames(i,2)));
for iSig=1:length(sig2Search)
Pos2Paste(sig2Search(iSig))=Pos2Paste(sig2Search(iSig))+1;
messageStruct(imes).Signals.(SigNames{sig2Search(iSig),1})
end
end
toc
However, I get an error in this line.
messageStruct(imes).Signals.(SigNames{sig2Search(iSig),1})
that works in case, I address to a single row, but not when I adress to several rows.

Sign in to comment.

Categories

Find more on Structures in Help Center and File Exchange

Products


Release

R2019b

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!