[英]In MATLAB, is cellfun always replaceable with arrayfun?
我在MATLAB 2007中找到了一個例子,其中cellfun
和arrayfun
幾乎可以互換使用:
>> cellfun(@(c) c, {'one' 'two' 'three'}, 'uniformoutput', 0)
% ans =
% 'one' 'two' 'three'
>> arrayfun(@(c) c, {'one' 'two' 'three'})
% ans =
% 'one' 'two' 'three'
我還可以想到一個示例,其中arrayfun
可以工作,但是cellfun
沒有:
>> arrayfun(@(c) c, [1 2 3])
% ans =
% 1 2 3
>> cellfun(@(c) c, [1 2 3])
% ??? Error using ==> cellfun
% Input #2 expected to be a cell array, was double instead.
我的問題是:在任何情況下, cellfun
有效,但是arrayfun
沒有嗎? 如果是,請舉例。 如果不是,為什么cellfun
甚至需要存在?
這是有趣的。 您的示例正在執行兩個不同的操作,這恰好會導致相同的結果。 這是一種探索的樂趣。
TL; DR。 通常,您應該使用arrayfun
當你輸入一個數組, cellfun
當你輸入一個單元格,雖然可以經常迫使arrayfun
做的工作,與語法地獄varyig水平。
從根本上說, arrayfun
意味着在數組上運行,而cellfun
意味着在單元上運行。 但是,Matlab明智地會注意到一個單元格只不過是一個“單元格”陣列,所以無論如何, arrayfun
可以工作。
正如您所指出的,以下兩行執行相同的操作:
cellfun(@(c) c, {'one' 'two' 'three'}, 'uniformoutput', 0) %returns {'one' 'two' 'three'}
arrayfun(@(c) c(1), {'one' 'two' 'three'}); %returns {'one' 'two' 'three'}
但是,如果我們想在操作過程中做些什么,那就有點不同了。 例如,我們可能想要提取每個字符串的第一個字符。 比較cellfun
和arrayfun
結果:
cellfun( @(c) c(1), {'one' 'two' 'three'}, 'uniformoutput', 0); %returns {'o' 't' 't'}
arrayfun(@(c) c(1), {'one' 'two' 'three'}); %Returns {'one' 'two' 'three'}
使用arrayfun得到相同的結果,我們需要取消引用匿名函數中的單元格,然后提取字符,然后將結果放入單元格數組而不是字符數組。 像這樣:
arrayfun(@(c) c{1}(1), {'one' 'two' 'three'},'uniformoutput',false) %Returns {'o' 't' 't'}
所以不同之處在於cellfun
負責解除引用操作,這是在循環時對單元的各個元素進行詳細操作所必需的(即{}
),而arrayfun
只執行標准索引(即()
)。 此外, 'uniformoutput',false
表示法確定輸出是寫入常規arral還是單元數組。
要顯示這在代碼中的含義,請參閱以下函數,這些函數等效於cellfun
和arrayfun
,包括和不包含'uniformoutput',false
表示法。 除了在循環中使用()
與{}
之外,這四個函數是等效的:
function out = cellFunEquivalent(fn, x)
for ix = numel(x):-1:1
out(ix) = fn(x{ix});
end
out = reshape(out,size(x));
end
function out = arrayFunEquivalent(fn, x)
for ix = numel(x):-1:1
out(ix) = fn(x(ix));
end
out = reshape(out,size(x));
end
function out = cellFunEquivalent_nonuniform(fn, x)
for ix = numel(x):-1:1
out{ix} = fn(x{ix});
end
out = reshape(out,size(x));
end
function out = arrayFunEquivalent_nonuniform(fn, x)
for ix = numel(x):-1:1
out{ix} = fn(x(ix));
end
out = reshape(out,size(x));
end
對於您發布的示例, arrayfun
函數實際上在單個元素單元格上運行,並將這些單元格的副本重建為同一(單元格)類的另一個數組(請參閱arrayFunEquivalent
)。 cellfun
操作取消引用輸入單元陣列的每個元素,然后將這些字符串的副本重建為單元格數組(請參閱cellFunEquivalent_nonuniform
)。 當輸入x
是單元格時,這些操作是等效的。
有一些內置函數可以在cellfun
按名稱引用,但不能在cellfun
中以相同的方式arrayfun
。 從幫助:
A = CELLFUN('fun', C), where 'fun' is one of the following strings,
returns a logical or double array A the elements of which are computed
from those of C as follows:
'isreal' -- true for cells containing a real array, false
otherwise
'isempty' -- true for cells containing an empty array, false
otherwise
'islogical' -- true for cells containing a logical array, false
otherwise
'length' -- the length of the contents of each cell
'ndims' -- the number of dimensions of the contents of each cell
'prodofsize' -- the number of elements of the contents of each cell
所以cellfun('isreal', {'one' 'two' 'three'})
是一個有效的表達式,但是任何與arrayfun
類似的調用都會觸發First input must be a function handle
錯誤。
當然,您可以將@isreal
或@isempty
用於arrayfun
至於為什么cellfun
仍然存在,我懷疑它是歷史的(不破壞向后兼容性)
cellfun()
存在主要是出於歷史原因 ,即至少從1998年開始,而arrayfun()
和structfun僅在2005年末在R14SP3版本中引入 。
此外,如所指出的Nirk在他的回答 , cellfun()
支持一些傳統的語法,限制在少數情況下,雖然,也就是通常比柄快@
對手。
閱讀兩份文件:
[B1,...,Bm] = arrayfun(func,A1,...,An)
...將數組A1,...,An
元素傳遞給函數func
,其中n
是輸入數。 ...第i
次迭代對應語法[B1(i),...,Bm(i)] = func(A1{i},...,An{i})
...
[A1,...,Am] = cellfun(func,C1,...,Cn)
調用函數handlefunc
指定的函數,並從單元格數組C1,...,Cn
傳遞元素...
因此,前者接受數組,而后者只接受數組。
濫用符號,在你的第一個例子中你有A1 = C1 = {'one' 'two' 'three'}
這是合法的,根據文檔,而在你的第二種情況A1 = [1 2 3]
但C1
不能是數字陣列。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.