1
votes

I have a folder include 10 excel files. Each of the excel file contain 5 sheets. I would like to

concatenate every 1st row in 1st sheet of each excel file into new sheet1 in new excel file named 'final' concatenate every 2nd row in 1st sheet of each excel file into new sheet1 in new excel file named 'final' concatenate every 3rd row in 1st sheet of each excel file into new sheet1 in new excel file named 'final' ....

then

concatenate every 1st row in 2nd sheet of each excel file into new sheet2 in new excel file named 'final' concatenate every 2nd row in 2nd sheet of each excel file into new sheet2 in new excel file named 'final' concatenate every 3rd row in 2nd sheet of each excel file into new sheet2 in new excel file named 'final' ....

repeatedly...do for all 5 sheets...

example:

excel file 1, sheet1

30  4   1.6 1.2 1.2 1.0
35  16  0.9 0.9 1.5 1.0
40  62  0.9 0.9 1.6 1.2
45  3   0.9 0.9 0.9 0.9
50  1   1.5 1.5 0.8 0.8

excel file 2, sheet1

10  1   0.8 0.9 0.9 0.9
15  31  0.9 0.9 1.2 1.6
20  2   0.9 0.9 0.9 0.9
25  3   0.9 0.9 0.9 0.9
30  18  0.9 0.9 0.9 0.9

excel file 3, sheet1 to excel file 10, sheet 1 etc...

the result i would like to get

final.xls, sheet1

30  4   1.6 1.2 1.2 1.0  %1st row of sheet1 in excel file 1
10  1   0.8 0.9 0.9 0.9  %1st row of sheet1 in excel file 2
... %repeated 1st row of sheet1 in excel file 3 to 10
35  16  0.9 0.9 1.5 1.0    %2nd row of sheet1 in excel file 1
15  31  0.9 0.9 1.2 1.6    %2nd row of sheet1 in excel file 2
... %repeated 2nd row of sheet1 in excel file 3 to 10

final.xls, sheet2

%similar to sheet1 just the data read from sheet2..

Does anyone can help me?

2

2 Answers

2
votes

I created 10 .xls files for testing with 5 sheets each. All sheets have 5x6 cells of random numbers. Here is my first solution:

%# get input XLS files
dName = uigetdir('.', 'Select folder containing Excel XLS files');
if dName==0, error('No folder selected'); end
files = dir( fullfile(dName,'*.xls') );
files = strcat(dName, filesep, {files.name}');    %'

%# prepare output XLS file
[fName dName] = uiputfile({'*.xls' 'Excel (*.xls)'}, 'Output File', 'final.xls');
if dName==0, error('No file selected'); end
fOut = fullfile(dName,fName);

%# process
NUM_SHEETS = 5;                       %# number of sheets per file
for s=1:NUM_SHEETS
    %# extract contents of same sheet from all files
    numData = cell(numel(files),1);
    for f=1:numel(files)
        numData{f} = xlsread(files{f}, s);
    end

    %# rearrange data
    numData = cat(3,numData{:});
    numData = reshape(permute(numData,[3 1 2]), [], size(numData,2));

    %# write data to corresponding sheet of output XLS file
    xlswrite(fOut, numData, s);
end

This was quite slow. It took around 3 minutes to finish... The reason is that a connection to Excel automation server is created then destroyed repeatedly in each call to XLSREAD/XLSWRITE. On the plus side, these two functions hide away a lot of the dirty work needed to interact with Excel, and expose an easy-to-use interface.

In my second solution, I manually call the Excel COM API. The advantage is that we initiate it only one time, and tear it down once we are finished, eliminating a lot of overhead. In fact, this code executes in less than 4 seconds!:

%# get input XLS files
dName = uigetdir('.', 'Select folder containing Excel XLS files');
if dName==0, error('No folder selected'); end
files = dir( fullfile(dName,'*.xls') );
files = strcat(dName, filesep, {files.name}');    %'

%# get output XLS file
[fName dName] = uiputfile({'*.xls' 'Excel (*.xls)'},'Output File','final.xls');
if dName==0, error('No file selected'); end
fOut = fullfile(dName,fName);

%# open Excel COM Server
Excel = actxserver('Excel.Application');
Excel.DisplayAlerts = 0;

%# prepare output
if ~exist(fOut, 'file')
    %# create if doesnt exist
    wb = Excel.workbooks.Add;
    wb.SaveAs(fOut,1);
    wb.Close(false);
else
    %# delete existing file
    delete(fOut);
end

%# extract contents of input files
NUM_SHEETS = 5;
data = cell(numel(files),NUM_SHEETS);
for f=1:numel(files)
    wb = Excel.Workbooks.Open(files{f}, 0, true); %# open XLS file for reading
    assert( wb.sheets.Count == NUM_SHEETS );
    for s=1:NUM_SHEETS                            %# loop over all sheets
        %# activate sheet, and extract entire content
        Excel.sheets.get('item',s).Activate();
        Excel.Range('A1').Activate();
        data{f,s} = cell2num( Excel.ActiveSheet.UsedRange.Value );
    end
    wb.Close(false);                              %# close XLS file
end

%# rearrange data
D = cell(NUM_SHEETS,1);
for s=1:NUM_SHEETS
    x = cat(3,data{:,s});
    D{s} = reshape(permute(x,[3 1 2]), [], size(x,2));
end

%# write data to sheets of output XLS file
wb = Excel.Workbooks.Open(fOut, 0, false);       %# open XLS file for writing
while Excel.Sheets.Count < NUM_SHEETS            %# create sheets as required
    Excel.Sheets.Add([], Excel.Sheets.Item(Excel.Sheets.Count));
end
for s=1:NUM_SHEETS                               %# write conents to each sheet
    cellRange = sprintf('A1:%s%d', 'A'+size(D{s},2)-1, size(D{s},1));
    wb.sheets.get('item',s).Activate();
    Excel.Range(cellRange).Select();
    set(Excel.selection, 'Value',num2cell(D{s}));
end
wb.Save();
wb.Close(false);                                 %# close XLS file

%# cleanup
Excel.Quit();
Excel.delete();
clear Excel;

I believe there are already submissions on the FEX that do a similar thing...

0
votes

I'll assume that you've saved each of your excel files as a csv named 'file1.csv', 'file2.csv', etc.
Creative use of the reshape command helps rearrange the rows.

num_row = 2;
num_col = 6;
num_file = 10;
c = cell(num_file ,1);
for i=1:num_file 
    file = sprintf('file%i.csv', i);
    x = csvread(file);
    c{i} = x'; % transpose so each row is a column
end
data = cell2mat(c);
data = reshape(data, num_col, num_row*num_file;
data = data'; transpose back