来自Matlab中的单元阵列的子串

时间:2013-10-10 15:10:40

标签: matlab cell-array

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

% 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 个答案:

答案 0 :(得分:4)

  

我无法一劳永逸地记下这些符号,如下所示:

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

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

  

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

当下标索引仅引用一个元素时,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{:});
    
  5. 有很多可供选择的解决方案,只需选择最适合您的解决方案:)我认为使用MATLAB的JIT加速,在大多数情况下,简单的循环就足够了。

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

答案 1 :(得分:3)

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

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

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

答案 2 :(得分:1)

你可以这样做:

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

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

答案 3 :(得分:1)

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

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

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