我是Matlab的初学者,想要对一个简单的表进行排序。我有一个包含.txt格式的数字和字母的表格:
K L M N O
1 1 a1 3b 1.72
2 1 2c 4d 1.43
3 1 e3 5f 1.33
4 1 g4 h5 1.64
1 2 4i 4j 1.48
2 2 6k l8 2.33
3 2 m7 8n 2.12
4 2 o8 p0 1.92
现在我想用Matlab对这个表进行排序。我想要的是:
K L M N O
1 1 a1 3b 1.72
1 2 4i 4j 1.48
2 1 2c 4d 1.43
2 2 6k l8 2.33
3 1 e3 5f 1.33
3 2 m7 8n 2.12
4 1 g4 h5 1.64
4 2 o8 p0 1.92
我想按第一列排序。之后我想让Matlab将结果保存在一个新的.txt文件中,或者打开我可以使用该表的Excel。这可能吗?
我尝试通过使用两个for循环来做到这一点,但是我遇到了很多错误。有没有一种简单的方法来做这个mit Matlab?
答案 0 :(得分:2)
假设您将数据放在名为test.txt
的文件中,格式如您所说
K L M N O
1 1 a1 3b 1.72
2 1 2c 4d 1.43
3 1 e3 5f 1.33
4 1 g4 h5 1.64
1 2 4i 4j 1.48
2 2 6k l8 2.33
3 2 m7 8n 2.12
4 2 o8 p0 1.92
然后以下代码执行您想要的操作
% Read the file column by column according to the specified format (all strings in this case) and separated by a delimiter (a blank space in this case). The resulting `K`, `L`, ... are cells.
[K, L, M, N, O] = textread('test.txt', '%s %s %s %s %s', 'delimiter', ' ');
% Remove the first element of the columns (i.e., the chars `K`, `L`, ...).
K(1) = [];
L(1) = [];
M(1) = [];
N(1) = [];
O(1) = [];
% Transform the cell into a matrix (a colum in this case) and sort it. The sorting returns also the position of the sorted column (variable `idx`).
[~, idx] = sort(cell2mat(K), 1, 'ascend');
% Put everything back together, re-adding the first letters and using the sorted indices.
X = [['K'; K(idx)], ['L'; L(idx)], ['M'; M(idx)], ['N'; N(idx)], ['O'; O(idx)]];
% Write to a xls file
xlswrite('newTest.xls', X);
修改强>
这是另一个可以读取任意数量的行和列的版本。它更灵活,但由于它与for
循环相关,因此很多行可能会变慢。例如,在我的计算机上,在文本文件中放置1000行和5列,第一个代码为1.1s
,第二个代码为2.2s
。
% Open the file, read it and close it.
fid = fopen('test.txt');
C = textscan(fid,'%s','delimiter','\n');
fclose(fid);
% textscan returns a 1-by-1 cell containing a N-by-1 cell array of strings.
% Since we used '\n' as delimiter, N will be the number of rows
C = C{1}; % explicitly take the cell
% Save the first row (with the names of the columns) an remove it for sorting
names = C(1,:);
C(1,:) = [];
% Sort the cells according to the rows
C = sort(C);
% Put the names back
C = [names; C];
% Split all the rows using the space as delimiter (default)
for i = 1 : numel(C)
C{i} = strsplit(C{i});
end
% Convert it to table and write to a xls file
C = cell2table(C);
writetable(C,'newTest.xls','WriteVariableNames',false)
% 'WriteVariableNames' avoids that default headlines will be put in the xls
编辑2
前面的代码将所有输入都视为字符串,因此在对行进行正确排序时会出现问题(例如,10
将在2
之前进行排序。
这个最终的解决方案解决了所有问题,它甚至比第二个解决方案更快。
% Read the file directly into a table
T = readtable('test.txt', 'Delimiter', ' ');
% Sort the rows according to the desired column (K in this case)
T = sortrows(T, 'K', 'ascend');
% To delete a column ('L' for instance)
T.L = [];
% Write the table into a xls file
writetable(T, 'newTest.xls', 'WriteVariableNames', true)
答案 1 :(得分:0)
在MATLAB中处理具有混合数据类型的文件可能相当不方便(就像你在这里:整数,字符串和浮点数)。一种选择是使用textscan()
,它使用formatSpec
参数来解析输入到单元格数组中。但是,如果列数很大,这可能很麻烦,并且将数据写回文件并不简单。在这些情况下,我建议采用以下解决方案,这在概念上很简单,但有些不优雅:
我假设您的数据是以下列格式的纯文本:
1 1 a1 3b 1.72
2 1 2c 4d 1.43
3 1 e3 5f 1.33
4 1 g4 h5 1.64
1 2 4i 4j 1.48
2 2 6k l8 2.33
3 2 m7 8n 2.12
4 2 o8 p0 1.92
根据第一列对数据行进行排序并将其写入新文件的脚本:
% read the data, ignoring types
A = dlmread('data.csv', ' ');
% get indices of the first column in sorted order
[~, indices] = sort(A(:,1));
% read each line of the file as a string into a cell array
fid = fopen('data.csv', 'rt');
lines = textscan(fid, '%s', 'delimiter', '\n');
fclose(fid);
% store lines sorted by first column in a new cell array
lines_sorted = {lines{:}{indices}};
% write sorted data to a new csv
fid = fopen('data_sorted.csv', 'wt');
fprintf(fid, '%s\n', lines_sorted{:});
fclose(fid);
输出:
1 1 a1 3b 1.72
1 2 4i 4j 1.48
2 1 2c 4d 1.43
2 2 6k l8 2.33
3 1 e3 5f 1.33
3 2 m7 8n 2.12
4 1 g4 h5 1.64
4 2 o8 p0 1.92
这里的魔力在s = {lines{:}{indices}}
行。这只是使用索引(按排序的第一列的顺序)索引文件中的行并将结果打包到新的单元格数组中。
注意:如果您的数据纯粹是数字化的(存储在矩阵A
中),您只需使用sortrows(A, 1)
按第一列排序。
此解决方案中使用的函数dlmread
无法在MATLAB中无错误地读取文本文件。但是,它确实适用于Octave。