2013-10-10 141 views
5

我是MATLAB新手,我很努力去理解數組和明智操作之間的細微差別。我正在處理一個大型數據集,我發現最簡單的方法並不總是最快的。我有一個字符串的一個非常大的單元陣列,像這樣簡單的例子: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

我不能工作了符號引用他們都在一氣呵成,就像這樣:

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的建議,將單元格數組轉換爲一個字符串數組(一個ch矩陣aracters),重塑它並提取所需的列:

    MyArrayOfSubStrings =vertcat(CellArrayOfStrings{:}); 
    MyArrayOfSubStrings = MyArrayOfSubStrings(:, 3:4); 
    
  4. 僱傭更多複雜的方法,如正則表達式:

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

有很多解決方案,挑選,只挑最適合你的一個:)我認爲用MATLAB的JIT加速,在大多數情況下,一個簡單的循環就足夠了。

另請注意,在我所有的建議中,獲得的子串單元格的單元數組被轉換爲一個字符串數組(矩陣)。這僅僅是爲了這個例子;顯然你可以保留子字符串存儲在單元格陣列中,如果你這樣決定的話。

+1

感謝您的全面回覆,這既回答了我的問題,也幫助了我的理解。最後我選擇了選項3,這對我的數據集和函數來說似乎是最好的選擇:我發現在我的函數(選項1)中使用For循環比用cellfun調用函數要慢4倍(選項2)。我選擇了選項3,因爲我不想向其他會使用這個:)的人解釋cellfun。還要感謝Dan和Moshen提供了類似的答案。 – fodfish

+0

很酷。因此,從(1)直接訪問由CellArray = textscan(fid,format)產生的二維單元格數組中的行,列,子字符串,其中col是文本列將是CellArray {col} {row}(3:4)。 –

1

你可以這樣做:

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

但是,只有當你的字符串都相等長度的我害怕。

3

cellfun操作單元陣列的每一個元素,所以你可以做這樣的事情:

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

如果你想字符串,而不是一個單元陣列,其元素爲字符串的矩陣,上使用charMyArrayOfSubstrings。請注意,只有每個字符串長度相同時才允許使用。

1

您可以使用char將它們轉換爲字符數組,做索引,並將其轉換回單元陣列

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

注意,如果字符串的長度不同,char墊用空格末創建數組。因此,如果您索引超出一個短字符串長度的列,則可能會收到一些空格字符。