2017-05-21 6 views
14

Używam funkcji cellfun do zastosowania funkcji do każdej komórki w tablicy komórek.Czy owijanie funkcji operatorem {} jest poprawnym zamiennikiem 'UniformOutput', false w cellfun?

Wiem, że muszę ustawić 'UniformOutput' na false, gdy funkcja zwraca wartości nie-skalarne, tak że wyjścia funkcji są zwracane hermetyzowane w tablicy komórek.

Take następującą tablicę komórek jako przykład:

C1 = {[1 2 3], [4 5 6]}; 

C1 ma dwie komórki, a każda komórka zawiera wektor z trzech elementów:

C1 = 

    1×2 cell array 

    [1×3 double] [1×3 double] 

Jeśli chcę dodać 1 do treści w każdej komórce mogę zdefiniować funkcję @(x) x + 1 i zastosować ją w następujący sposób:

C2 = cellfun(@(x) x + 1, C1, 'UniformOutput', false); 

Działa to bardzo dobrze, ale zauważ, że muszę się upewnić, że 'UniformOutput' jest ustawione na false, jak już wcześniej wyjaśniłem, w przeciwnym razie zostanie zgłoszony błąd.

Jednak po przeczytaniu this thread, zdałem sobie sprawę, że jeśli będę owijać funkcji z cell array construction operator {} jak ta @(x) {x + 1} potem nie trzeba ustawić 'UniformOutput' do false.

więc następujące polecenie generuje takie same wyniki jak w C2 bez rzuca wszelkie błędy:

C3 = cellfun(@(x) {x + 1}, C1); 

chodzi o układ kodu wolę takie podejście, ponieważ jest bardziej zwarty i mniej gadatliwy niż poprzednio, ale Nie jestem pewien, czy to zawsze jest bezpieczne.


Tak więc moje pytanie brzmi:

zawsze mogę zawinąć funkcję z {} uniknąć ustawiania 'UniformOutput' do false? Czy są jakieś scenariusze, w których takie zastąpienie nie zadziałałoby?


Moje badania:

help cellfun 

'UniformOutput' - wartość logiczną wskazującą, czy wyjście (s) z FUN może być zwrócony bez hermetyzacji w komórce tablicy. Jeśli true (domyślnie), FUN musi zwracać wartości skalarne, które mogą być łączone w macierz. Jeśli true, wyjścia muszą być następujące typy: numeryczne, logiczne, char, struct, komórka. Jeśli false, , cellfun zwraca tablicę komórek (lub wiele macierzy komórek), , gdzie komórka (I, J, ...) th zawiera wartość FUN (C {I, J, ...}, ...) . Gdy 'UniformOutput' to false, wyjścia mogą być dowolnego typu.

Poniższy fragment jest częścią an answer powiązanemu pytanie:

[...] cellfun dba operacji dereference która obowiązek zrobić szczegółowe operacji na poszczególnych elementach komórce kiedy pętli (czyli {}) [...]

Odpowiedz

15

Istnieją dwa scenariusze mogę myśleć, gdzie w użyciu cell encapsulation Zamiast dodatkowych argumentów ...'UniformOutput', false) spowoduje problem, najpierw jedna jest znacznie bardziej prawdopodobny niż drugi:

  • Przechwytywanie wiele wyjść: Czasami chcesz uchwycić wiele wyjść z funkcji jesteś zastosowanie, na przykład wywołanie unique na każdym elemencie macierzy komórek i uzyskanie dodatkowych argumentów indeksu. Korzystanie ...'UniformOutput', false) możemy łatwo to zrobić:

    >> C1 = {[1 2 3], [4 5 6]}; 
    >> [C2, index] = cellfun(@(x) unique(x), C1, 'UniformOutput', false) 
    C2 = 
        1×2 cell array 
        [1×3 double] [1×3 double] 
    index = 
        1×2 cell array 
        [3×1 double] [3×1 double] 
    

    to jednak nie przy użyciu enkapsulacji komórek:

    >> [C2, index] = cellfun(@(x) {unique(x)}, C1) 
    Output argument "varargout{2}" (and maybe others) not assigned during call to 
    "@(x){unique(x)}". 
    
  • funkcji bez wyjścia: Wiem o czym myślisz: „Ale jeśli nie produkują wyjścia, to nie muszę się martwić o zbieranie wartości nieskalarnych! " To prawda, ale wyobrażam sobie niewątpliwie niecodzienny scenariusz, w którym funkcja, która ma być oceniona, może być dodatkowym parametrem, takim jak uchwyt funkcji przekazywany jako argument, więc nie wiesz, 01:08:00, do czynienia z. Niezależnie od tego, te dwa podejścia różnią się w takim przypadku:

    >> C1 = {[1 2 3], [4 5 6]}; 
    >> cellfun(@(x) disp(x), C1, 'UniformOutput', false); 
        1  2  3 
        4  5  6 
    
    >> cellfun(@(x) {disp(x)}, C1); 
    Error using disp 
    Too many output arguments. 
    Error in @(x){disp(x)} 
    

    prawdopodobnie nie coś ty kiedykolwiek się martwić, ale myślałem, że to nie przez wzgląd na kompletność.

+0

Wow..Nie wiedziałem, że przechwytywanie wielu wyjść z 'cellfun' było nawet możliwe. To jest pouczająca odpowiedź! Dziękuję Ci :) – codeaviator

2

od ciebie pytanie ...

zawsze mogę zawinąć funkcji z {}, aby uniknąć ustawiania 'UniformOutput' false? Czy są jakieś scenariusze, w których takie zastąpienie nie zadziałałoby?

Krótka odpowiedź to "NIE". Uważam, że głównym powodem, dla którego twoja anonimowa funkcja zawodzi, jest brak kontroli typów, a programista ma niewielką wiedzę na temat zwracania funkcji.

W rzeczywistości, IMO, nie powinieneś walczyć z wykorzystaniem operatora indeksowania komórek {}, aby zawinąć swoją wartość zwracaną lub nie w anonimowej funkcji. Lepszą praktyką będzie określenie typu wartości zwracanej po wywołaniu cellfun lub sprawdzenie typu wartości wejściowej przed wywołaniem cellfun. Oczywiście, możesz wdrożyć procedurę sprawdzania typu lub try...catch w swoim function handle, a także zapewnić pełną kontrolę nad swoim typem zwrotu. I szczerze mówiąc, wiedza o tym, co wyślesz i co otrzymasz, jest niezwykle ważna w Matlabie.

W skrócie, nie powinieneś używać {} do enkapsulacji swojej anonimowej funkcji, chyba że celowo utworzysz tablicę komórek jako typ zwrotu i wiesz, że można użyć wartości zwracanej z funkcji, którą wywołałeś. aby utworzyć tablicę komórek.

Do Twojej wiadomości, jeśli masz 2016b lub nowszy, a function in script is possible, możesz utworzyć uchwyt funkcji dla cellfun w swoim skrypcie bez tworzenia nowego pliku.

Powiązane problemy