【问题标题】:Substrings from a Cell Array in MatlabMatlab中单元格数组的子字符串
【发布时间】:2013-10-10 15:10:40
【问题描述】:

我是 MATLAB 新手,我正在努力理解数组操作和元素操作之间的微妙之处。我正在处理一个大型数据集,我发现最简单的方法并不总是最快的。我有一个非常大的字符串元胞数组,就像在这个简化的例子中一样:

% A vertical array of same-length strings
CellArrayOfStrings = {'aaa123'; 'bbb123'; 'ccc123'; 'ddd123'};

我正在尝试提取一个子字符串数组,例如:

'a1'
'b1'
'c1'
'd1'

我很高兴有这样的元素参考:

% Simple element-wise substring operation
MySubString = CellArrayOfStrings{2}(3:4);  % Expected result is 'b1'

但我无法计算出一次性引用它们的符号,如下所示:

% Desired result is 'a1','b1','c1','d1'
MyArrayOfSubStrings = CellArrayOfStrings{:}(3:4); % Incorrect notation!

我知道 Matlab 能够执行非常快速的数组操作,例如 strcat,所以我希望有一种技术能够以类似的速度工作:

% An array-wise operation which works quickly
tic
speedTest = strcat(CellArrayOfStrings,'hello');
toc   % About 2 seconds on my machine with >500K array elements

我尝试过的所有使用幕后迭代的 for 循环和函数在我的数据集上运行得太慢。是否有一些数组符号可以做到这一点?有人能纠正我对元素和数组操作的理解吗?!非常感谢!

【问题讨论】:

    标签: matlab cell-array


    【解决方案1】:

    我无法计算出一次性引用它们的符号,如下所示:

    MyArrayOfSubStrings = CellArrayOfStrings{:}(3:4); % Incorrect notation!

    这是因为花括号({})返回一个comma-separated list,相当于将这些单元格的内容写成如下方式:

    c{1}, c{2}, <i>and so on</i>....

    当下标索引仅引用 一个 元素时,MATLAB 的语法允许在花括号后使用括号 (()) 并进一步提取子数组(在您的情况下为子字符串)。但是,当逗号分隔的列表包含多个项目时,禁止使用此语法。

    那么有什么替代品呢?

    1. 使用for loop

      MyArrayOfSubStrings = char(zeros(numel(CellArrayOfStrings), 2));
      for k = 1:size(MyArrayOfSubStrings, 1)
          MyArrayOfSubStrings(k, :) = CellArrayOfStrings{k}(3:4);
      end
      
    2. 使用cellfunDang Khoa's 答案的轻微变体):

      MyArrayOfSubStrings = cellfun(@(x){x(3:4)}, CellArrayOfStrings);
      MyArrayOfSubStrings = vertcat(MyArrayOfSubStrings{:});
      
    3. 如果您的原始元胞数组包含固定长度的字符串,您可以按照Dan 的建议将元胞数组转换为字符串数组(字符矩阵),对其进行整形并提取所需的列:

      MyArrayOfSubStrings =vertcat(CellArrayOfStrings{:});
      MyArrayOfSubStrings = MyArrayOfSubStrings(:, 3:4);
      
    4. 采用更复杂的方法,比如正则表达式:

      MyArrayOfSubStrings = regexprep(CellArrayOfStrings, '^..(..).*', '$1');
      MyArrayOfSubStrings = vertcat(MyArrayOfSubStrings{:});
      

    有很多解决方案可供选择,只需选择最适合您的解决方案即可:) 我认为使用 MATLAB 的 JIT 加速,在大多数情况下,一个简单的循环就足够了。

    另请注意,在我的所有建议中,获得的子字符串单元格数组单元格都被转换为字符串数组(矩阵)。这只是为了示例;显然,如果您决定这样做,您可以将子字符串存储在单元数组中。

    【讨论】:

    • 感谢您的全面回复,既回答了我的问题,也帮助了我的理解。最后,我选择了选项 3,这似乎是我的数据集和函数的最佳选项:我发现在函数中使用 For 循环(选项 1)比使用 cellfun 调用函数(选项 2)慢大约 4 倍。我选择了选项 3,因为我不想向其他将使用它的人解释 cellfun :)。还要感谢提供类似答案的 Dan 和 Moshen。
    • 酷。因此,从 (1) 直接访问由 CellArray=textscan(fid,format) 生成的二维单元格数组中的行、列、子字符串,其中 col 是文本列将是 CellArray{col}{row}(3:4)。
    【解决方案2】:

    cellfun 对元胞数组的每个元素进行操作,因此您可以执行以下操作:

    >> CellArrayOfStrings = {'aaa123'; 'bbb123'; 'ccc123'; 'ddd123'};
    >> MyArrayofSubstrings = cellfun(@(str) str(3:4), CellArrayOfStrings, 'UniformOutput', false)
    MyArrayofSubstrings = 
        'a1'
        'b1'
        'c1'
        'd1'
    

    如果您想要一个字符串矩阵而不是一个以字符串为元素的元胞数组,请在MyArrayOfSubstrings 上使用char。请注意,仅当每个字符串的长度相同时才允许这样做。

    【讨论】:

      【解决方案3】:

      你可以这样做:

      C = {'aaa123'; 'bbb123'; 'ccc123'; 'ddd123'}
      t = reshape([C{:}], 6, [])'
      t(:, 3:4)
      

      但恐怕只有你的字符串长度相等。

      【讨论】:

        【解决方案4】:

        您可以使用char 将它们转换为字符数组,进行索引并将其转换回元胞数组

        A = char(CellArrayOfStrings);
        B = cellstr(A(:,3:4));
        

        请注意,如果字符串的长度不同,char 在末尾用空格填充它们以创建数组。因此,如果您为超过其中一个短字符串长度的列建立索引,您可能会收到一些空格字符。

        【讨论】:

          猜你喜欢
          • 2014-03-22
          • 1970-01-01
          • 2019-05-24
          • 2015-10-18
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2014-01-11
          • 1970-01-01
          相关资源
          最近更新 更多