6

我是 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 循环和函数在我的数据集上运行得太慢。是否有一些数组符号可以做到这一点?有人能纠正我对元素和数组操作的理解吗?!非常感谢!

4

4 回答 4

5

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

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

这是因为花括号 ( {}) 返回一个逗号分隔的列表,相当于将这些单元格的内容写成如下方式:

c{1}, c{2}, and so on....

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

那么有哪些替代方案呢?

  1. 使用for循环

    MyArrayOfSubStrings = char(zeros(numel(CellArrayOfStrings), 2));
    for k = 1:size(MyArrayOfSubStrings, 1)
        MyArrayOfSubStrings(k, :) = CellArrayOfStrings{k}(3:4);
    end
    
  2. 使用cellfunDang Khoa回答的一个小变种):

    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 加速,在大多数情况下,一个简单的循环就足够了。

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

于 2013-10-10T15:37:46.590 回答
4

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

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

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

于 2013-10-10T15:25:05.407 回答
1

你可以这样做:

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

但只有当你的琴弦长度相等时,我才害怕。

于 2013-10-10T15:18:24.353 回答
1

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

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

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

于 2013-10-11T08:10:11.257 回答