65 views (last 30 days)
Show older comments
Jackson Kock on 23 Apr 2021
Answered: Stephen23 on 24 Apr 2021
Accepted Answer: dpb
Open in MATLAB Online
Dear All,
I want to avoid the use of for loops by using the structfun() and cellfun() commands.
I have a folder with a bunch of "nnn_M.csv" files, where the "nnn" prefix corresponds to numbering of the files, and the "_M" suffix being constant for all files. My goal is to create a double array of the "nnn" values.
The code I currently use with a for loop: (Works)
Files = dir('*.csv'); % Create the structure of file descriptions (name,datenum,...)
N = length(Files); % Determind # of files for the for loop
for ii = 1:N
FileNames{ii} = Files(ii).name; % Create cell array of the file names
nnn(ii) = sscanf(FileNames{ii},'%d_M'); % Create double array of file prefixes
end
This is the code without a for loop: (Does not work)
Files = dir('*.csv'); % Create the structure of file descriptions (name,datenum,...)
FileNames = structfun(@(x) Files(x).name, Files); % Create cell array of the file names
nnn = cellfun(@(x) sscanf(FileNames{x},'%d_M'),FileNames); % Create double array of file prefixes
The 2nd and 3rd lines give me errors, repectively:
Error using structfun
Inputs to STRUCTFUN must be scalar structures.
% and
Index exceeds the number of array elements (14).
Error in @(x)sscanf(FileNames{x},'%dK')
% When using the correct 'FileNames' the for loop gives
% There are 14 *.csv files in the folder
I welcome all suggestions you may have. Thank you for helping me understand these functions!
Cheers,
-Jackson
0 Comments Show -2 older commentsHide -2 older comments
Show -2 older commentsHide -2 older comments
Sign in to comment.
Sign in to answer this question.
Accepted Answer
dpb on 24 Apr 2021
Open in MATLAB Online
As the error message and doc says, structfun applies a function to each field in a scalar struct; you have a struct array -- not what you want.
And, for the specific desire you don't need either function nor a loop construct, either -- use MATLAB vectorized notation--
nums=str2double(extractBefore(string({Files.name}),'_'));
2 Comments Show NoneHide None
Show NoneHide None
Jackson Kock on 24 Apr 2021
Direct link to this comment
https://www.mathworks.com/matlabcentral/answers/811680-understanding-the-structfun-or-cellfun-commands#comment_1479700
Open in MATLAB Online
Thank you dpb for the answer, which does work as needed.
A couple follow up comments/ questions if I may:
1) I learned that the {} around Files.name creates the cell array of the file names. Such as,
A = {Files.name};
The reason I need to {} is to create the array? Otherwise the command,
A = Files.name;
only knows to grab the first file's name?
2) I do not understand my initial error with the cellfun() command. If you couple please enlighten me on this regard. It seems like the function was doing something but the indexing was incorrect?
3) Could I still use a cellfun() to get the numbers in front of the file name? For example:
A = {Files.name};
B = cellfun(??,A); % I do not know what to put here
I want to understand how to use an arbitrary function inside the cellfun() command to be able to use them in the future. I understand the case of simpler functions, such as:
C = {[1,2],[3,4]};
D = cellfun(@mean,C);
Most appreciated.
dpb on 24 Apr 2021
Direct link to this comment
https://www.mathworks.com/matlabcentral/answers/811680-understanding-the-structfun-or-cellfun-commands#comment_1479950
Edited: dpb on 24 Apr 2021
Open in MATLAB Online
1) Try at the command line and see what Files.name returns. (Hint: search for "comma-separated list" in doc)
2) Since the first failed, I don't know what the content of the cell array was when you tried it so it's not possible to say just what, but probably you had a smaller array than thought and passed inconsistent ones
3a) Sure, but why? You want to avoid loops; cellfun is a loop in sheep's clothing; underneath it is the loop with more overhead than just the direct for...end construct. It has its place, certainly, but isn't always the better solution. But, for illustration
>> cellfun(@(s)sscanf(s,'%d_M'),{Files.name})
ans =
0 1.00
>>
3b) As the above illustrates, you write an anonymous function in place of the function handle--it can be any one-line expression. Or, if you can't manage it in one line, use a handle to the m-file function you write. NB: one feature of anonymous functions is that the embed any workspace variables not in their argument list in the function body itself -- the same result as above could be obtained by
>> arrayfun(@(i)sscanf(Files(i).name,'%d_M'),1:numel(Files))
ans =
0 1.00
>>
where the Files struct is embedded in the anonymous function. While not optimal here, this can be extremely useful when other parameters are needed to evaluate the function.
Sign in to comment.
More Answers (1)
Stephen23 on 24 Apr 2021
Open in MATLAB Online
- 1.2_M.csv
- 3.4_M.csv
- 5.6_M.csv
Avoiding CELLFUN or STRUCTFUN is simpler and much more efficient:
S = dir('*_M.csv');
V = sscanf([S.name],'%f_M.csv')
V = 3×1
1.2000 3.4000 5.6000
0 Comments Show -2 older commentsHide -2 older comments
Show -2 older commentsHide -2 older comments
Sign in to comment.
Sign in to answer this question.
See Also
Categories
MATLABLanguage FundamentalsData TypesData Type IdentificationWhos
Find more on Whos in Help Center and File Exchange
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!
An Error Occurred
Unable to complete the action because of changes made to the page. Reload the page to see its updated state.
Select a Web Site
Choose a web site to get translated content where available and see local events and offers. Based on your location, we recommend that you select: .
You can also select a web site from the following list
Americas
- América Latina (Español)
- Canada (English)
- United States (English)
Europe
- Belgium (English)
- Denmark (English)
- Deutschland (Deutsch)
- España (Español)
- Finland (English)
- France (Français)
- Ireland (English)
- Italia (Italiano)
- Luxembourg (English)
- Netherlands (English)
- Norway (English)
- Österreich (Deutsch)
- Portugal (English)
- Sweden (English)
- Switzerland
- Deutsch
- English
- Français
- United Kingdom(English)
Asia Pacific
- Australia (English)
- India (English)
- New Zealand (English)
- 中国
- 日本Japanese (日本語)
- 한국Korean (한국어)
Contact your local office