【问题标题】:Making a struct from a string containing matrices and its names从包含矩阵及其名称的字符串创建结构
【发布时间】:2017-08-21 15:38:16
【问题描述】:

我实际上有一个包含 uint8 数据的文本文件,如下所示:

[0, 18, 121] bl
[0, 19, 12] gt
[24, 19, 22] apa
[0, 18, 1] bl
[24, 19, 22] apa bpa
[1, 2, 3] apa

我最终想要的是一个结构,比如A,其中包含这些数据的字段为:

A.bl= [0, 18, 121;
       0, 18, 1  ];
A.gt = [0, 19, 12];
A.apa = [24,19,22];
A.apa_bpa = [24,19, 22]    or A.apabpa= [24, 19, 22]

所以上面的例子展示的是找到矩阵的多个实例并将它们堆叠成一个。如果名称中有空格,请删除空格或将其替换为下划线。

到目前为止,我有:

A = importdata('file.txt');

创建一个包含数据的元胞数组(我的原始数据为 20,000 x 1)。我已经知道文本文件将具有的矩阵的名称。所以我试图区分矩阵,如下所示,这给了我包含矩阵及其名称的单元格:

A(~cellfun(@isempty, strfind(A,'bl')))

我该如何进行?或者以更快的速度解决这个问题的更简单的方法是什么?

【问题讨论】:

    标签: matlab text struct cell-array


    【解决方案1】:

    在这种情况下,我会使用 textscan 而不是 importdata,因为您正在处理混合数据类型:

    fid = fopen('file.txt');
    data = textscan(fid, '[%d%d%d%s', 'Delimiter', ',]', 'CollectOutput', true);
    fclose(fid);
    values = data{1};
    fields = data{2};
    

    valuesfields 中为您提供以下结果:

    values =
      6×3 int32 matrix
    
         0    18   121
         0    19    12
        24    19    22
         0    18     1
        24    19    22
         1     2     3
    
    fields =
      6×1 cell array
    
        'bl'
        'gt'
        'apa'
        'bl'
        'apa bpa'
        'apa'
    

    现在您可以使用strrepfields 中的空格替换为下划线,使用unique 查找唯一字符串,使用accumarray 获取每个字符串的重复次数,sort values 的行匹配唯一字段名称列表,并使用 mat2cellvalues 的行进行分组:

    [fields, ~, index] = unique(strrep(fields, ' ', '_'));
    counts = accumarray(index, 1);
    [~, sortIndex] = sort(index);
    values = mat2cell(values(sortIndex, :), counts);
    

    现在您可以使用cell2struct 轻松地将它们组合成一个结构:

    S = cell2struct(values, fields)
    
    S = 
      struct with fields:
    
            apa: [2×3 int32]
        apa_bpa: [24 19 22]
             bl: [2×3 int32]
             gt: [0 19 12]
    

    【讨论】:

      【解决方案2】:

      如果您的文件相当长,格式正确,并且您不想在 eval 中使用糟糕的东西,我建议您通过 setfield 使用旧样式的设置结构字段

      % I just copied data from top of the post to the document
      fid = fopen('testdoc.txt');
      store_struct = struct();
      while ~feof(fid)
          tmp_line = fgetl(fid);
          delim_idx = find(tmp_line == ']');
          tmp_mat=uint8(str2num(tmp_line(2:delim_idx-1)));
          tmp_field = deblank(tmp_line(delim_idx+2:length(tmp_line)));
          tmp_field(tmp_field == ' ') = '_';
          if isfield(store_struct,tmp_field)
              store_struct = setfield(store_struct,tmp_field,...
                  [getfield(store_struct,tmp_field);tmp_mat]);
          else
              store_struct = setfield(store_struct,tmp_field,...
                  tmp_mat);
          end
      end
      fclose(fid);
      

      【讨论】:

      • 谢谢。执行需要一些时间,但会给出预期的输出。
      • 如果你确定你有足够的内存,gnovice 的方法更可取,尤其是因为它不会产生 IO 开销。如果您的 txt 文件是 Gb 大小,我的方法将很有用。
      【解决方案3】:

      你可以使用textscan作为gnovice的建议来读取数据

      fid = fopen('file.txt');
      data = textscan(fid, '[%d%d%d%s', 'Delimiter', ',]', 'CollectOutput', true);
      fclose(fid);
      values = data{1};
      fields = data{2};
      

      然后使用一个简单的循环来创建结构,因为您可以使用圆括号通过字符串访问结构的字段

      % demo for accessing fields
      myStruct.myField 
      % is equivalent to
      myStruct.('myField')
      

      所以:

      % Replace spaces with underscores in 'fields'
      fields = strrep(fields, ' ', '_');
      % Initialise struct
      A = struct;
      % Loop over fields, assign values
      for ii = 1:numel(fields)
          if isfield(A,fields{ii})
              % Append to array if field already exists
              A.(fields{ii}) = [A.(fields{ii}); values(ii,:)];
          else
              % Create field as array if doesn't yet exist
              A.(fields{ii}) = values(ii,:);
          end
      end
      

      【讨论】:

      • 这很有帮助。
      猜你喜欢
      • 1970-01-01
      • 2022-01-08
      • 2013-05-28
      • 2013-02-21
      • 2022-07-25
      • 1970-01-01
      • 2014-11-10
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多