簡體   English   中英

在MATLAB中,cellfun是否總是可以用arrayfun替換?

[英]In MATLAB, is cellfun always replaceable with arrayfun?

我在MATLAB 2007中找到了一個例子,其中cellfunarrayfun幾乎可以互換使用:

>> 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'}

但是,如果我們想在操作過程中做些什么,那就有點不同了。 例如,我們可能想要提取每個字符串的第一個字符。 比較cellfunarrayfun結果:

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還是單元數組。

要顯示這在代碼中的含義,請參閱以下函數,這些函數等效於cellfunarrayfun ,包括和不包含'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)調用函數handle func指定的函數,並從單元格數組C1,...,Cn傳遞元素...

因此,前者接受數組,而后者只接受數組。

濫用符號,在你的第一個例子中你有A1 = C1 = {'one' 'two' 'three'}這是合法的,根據文檔,而在你的第二種情況A1 = [1 2 3]C1不能是數字陣列。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM