Sök…


Användbara funktioner som fungerar på celler och matriser

Detta enkla exempel ger en förklaring till några funktioner som jag tyckte extremt användbara eftersom jag började använda MATLAB: cellfun , arrayfun . Tanken är att ta en array eller cellklassvariabel, slinga genom alla dess element och tillämpa en dedikerad funktion på varje element. En tillämpad funktion kan antingen vara anonym, vilket vanligtvis är fallet eller någon vanlig funktion definieras i en * .m-fil.

Låt oss börja med ett enkelt problem och säga att vi måste hitta en lista med * .mat-filer med mappen. För det här exemplet, låt oss först skapa några * .mat-filer i en aktuell mapp:

for n=1:10; save(sprintf('mymatfile%d.mat',n)); end

Efter att koden har körts bör det finnas 10 nya filer med förlängning * .mat. Om vi kör ett kommando för att lista alla * .mat-filer, till exempel:

mydir = dir('*.mat');

vi bör få en rad element i en direkt struktur; MATLAB ska ge en liknande utgång till den här:

10x1 struct array with fields:
    name
    date
    bytes
    isdir
    datenum

Som ni kan se är varje element i denna matris en struktur med ett par fält. All information är verkligen viktig för varje fil men i 99% är jag ganska intresserad av filnamn och inget annat. För att extrahera information från en strukturuppsättning, brukade jag skapa en lokal funktion som skulle innebära att skapa temporära variabler av rätt storlek, för slingor, extrahera ett namn från varje element och spara det i skapad variabel. Mycket enklare sätt att uppnå exakt samma resultat är att använda en av de nämnda funktionerna:

mydirlist = arrayfun(@(x) x.name, dir('*.mat'), 'UniformOutput', false)
mydirlist = 
    'mymatfile1.mat'
    'mymatfile10.mat'
    'mymatfile2.mat'
    'mymatfile3.mat'
    'mymatfile4.mat'
    'mymatfile5.mat'
    'mymatfile6.mat'
    'mymatfile7.mat'
    'mymatfile8.mat'
    'mymatfile9.mat'

Hur fungerar den här funktionen? Det tar vanligtvis två parametrar: ett funktionshandtag som den första parametern och en matris. En funktion fungerar sedan på varje element i en given grupp. De tredje och fjärde parametrarna är valfria men viktiga. Om vi vet att en utgång inte kommer att vara regelbunden måste den sparas i cellen. Detta måste UniformOutput ställa false för UniformOutput . Som standard försöker denna funktion att returnera en vanlig utgång, t.ex. en siffervektor. Låt oss till exempel extrahera information om hur mycket skivutrymme som tas av varje fil i byte:

mydirbytes = arrayfun(@(x) x.bytes, dir('*.mat'))
mydirbytes =
       34560
       34560
       34560
       34560
       34560
       34560
       34560
       34560
       34560
       34560

eller kilobyte:

mydirbytes = arrayfun(@(x) x.bytes/1024, dir('*.mat'))
mydirbytes =
   33.7500
   33.7500
   33.7500
   33.7500
   33.7500
   33.7500
   33.7500
   33.7500
   33.7500
   33.7500

Denna gång är utgången en vanlig dubbelvektor. UniformOutput sattes som true standard.

cellfun är en liknande funktion. Skillnaden mellan denna funktion och arrayfun är att cellfun fungerar på cellfun . Om vi bara vill extrahera namn som ges en lista med filnamn i en cell "mydirlist", behöver vi bara köra den här funktionen enligt följande:

mydirnames = cellfun(@(x) x(1:end-4), mydirlist, 'UniformOutput', false)
mydirnames = 
    'mymatfile1'
    'mymatfile10'
    'mymatfile2'
    'mymatfile3'
    'mymatfile4'
    'mymatfile5'
    'mymatfile6'
    'mymatfile7'
    'mymatfile8'
    'mymatfile9'

Återigen, eftersom en utgång inte är en vanlig vektor med siffror, måste en utgång sparas i en cellvariabel.

I exemplet nedan kombinerar jag två funktioner i en och returnerar bara en lista över filnamn utan en förlängning:

cellfun(@(x) x(1:end-4), arrayfun(@(x) x.name, dir('*.mat'), 'UniformOutput', false), 'UniformOutput', false)
ans = 
    'mymatfile1'
    'mymatfile10'
    'mymatfile2'
    'mymatfile3'
    'mymatfile4'
    'mymatfile5'
    'mymatfile6'
    'mymatfile7'
    'mymatfile8'
    'mymatfile9'

Det är galen men mycket möjligt eftersom arrayfun returnerar en cell som förväntas inmatning av cellfun ; en sidoanteckning till detta är att vi kan tvinga någon av dessa funktioner att returnera resultat i en UniformOutput att uttryckligen ställa UniformOutput till falsk. Vi kan alltid få resultat i en cell. Vi kanske inte kan få resultat i en vanlig vektor.

Det finns en mer liknande funktion som fungerar på fält en struktur: structfun . Jag har inte särskilt tyckt att det är lika användbart som de andra två, men det skulle lysa i vissa situationer. Om man till exempel vill veta vilka fält som är numeriska eller icke-numeriska, kan följande kod ge svaret:

structfun(@(x) ischar(x), mydir(1))

Det första och det andra fältet i en dir-struktur är av en koltyp. Därför är utgången:

 1
 1
 0
 0
 0

Utgången är också en logisk vektor av true / false . Följaktligen är det regelbundet och kan sparas i en vektor; inget behov av att använda en cellklass.

Inställningar för fällning av kod

Det är möjligt att ändra Code Folding-preferenser för att passa ditt behov. Således kan kodfällning ställas in aktivera / oförmögen för specifika konstruktioner (ex: if block , for loop , Sections ...).

För att ändra vikningsinställningar, gå till Inställningar -> Kodfällning:

ange bildbeskrivning här

Sedan kan du välja vilken del av koden som kan vikas.

Lite information:

  • Observera att du också kan utöka eller kollapsa hela koden i en fil genom att placera markören var som helst i filen, högerklicka och sedan välja Kodfällning> Expandera alla eller Kodfällning> Fäll allt från snabbmenyn.
  • Observera att vikningen är ihållande, i den meningen att en del av koden som har utvidgats / kollaps kommer att behålla sin status efter Matlab eller m-filen har stängts och öppnas igen.

Exempel: För att aktivera vikning för sektioner:

Ett intressant alternativ är att aktivera att fälla avsnitt. Avsnitt avgränsas av två %% ( %% ).

Exempel: För att aktivera det markerar du rutan "Sektioner":

ange bildbeskrivning här

I stället för att se en lång källkod som liknar:

ange bildbeskrivning här

Du kommer att kunna vika sektioner för att ha en allmän översikt över din kod: ange bildbeskrivning här

Extrahera siffrsdata

Vid några tillfällen har jag haft en intressant siffra som jag räddade men jag tappade åtkomsten till dess data. Detta exempel visar ett trick hur man kan få fram information från en figur.

De viktigaste funktionerna är findobj och get . findobj returnerar en hanterare till ett objekt som ges attribut eller egenskaper för objektet, till exempel Type eller Color , etc. När ett radobjekt har hittats, kan get returnera alla värden som innehas av egenskaper. Det visar sig att Line innehåller alla data i följande egenskaper: XData , YData och ZData ; den sista är vanligtvis 0 om inte en figur innehåller ett 3D-diagram.

Följande kod skapar ett exempel som visar två linjer en sinfunktion och en tröskel och en legend

t = (0:1/10:1-1/10)';
y = sin(2*pi*t);
plot(t,y);
hold on;
plot([0 0.9],[0 0], 'k-');
hold off;
legend({'sin' 'threshold'});

Den första användningen av findobj returnerar två hanterare till båda linjerna:

findobj(gcf, 'Type', 'Line')
ans = 
  2x1 Line array:

  Line    (threshold)
  Line    (sin)

För att begränsa resultatet kan findobj också använda en kombination av logiska operatörer -and , -or och egendomsnamn. Till exempel kan jag hitta ett DiplayName vars DiplayName är sin och läsa dess XData och YData .

lineh = findobj(gcf, 'Type', 'Line', '-and', 'DisplayName', 'sin');
xdata = get(lineh, 'XData');
ydata = get(lineh, 'YData');

och kontrollera om uppgifterna är lika.

isequal(t(:),xdata(:))
ans =
     1
isequal(y(:),ydata(:))
ans =
     1

På liknande sätt kan jag begränsa mina resultat genom att utesluta den svarta linjen (tröskel):

lineh = findobj(gcf, 'Type', 'Line', '-not', 'Color', 'k');
xdata = get(lineh, 'XData');
ydata = get(lineh, 'YData');

och den sista kontrollen bekräftar att data som extraherats från denna siffra är desamma:

isequal(t(:),xdata(:))
ans =
     1
isequal(y(:),ydata(:))
ans =
     1

Funktionell programmering med anonyma funktioner

Anonyma funktioner kan användas för funktionell programmering. Det huvudsakliga problemet att lösa är att det inte finns något naturligt sätt att förankra en rekursion, men det kan fortfarande implementeras på en enda rad:

if_ = @(bool, tf) tf{2-bool}();

Denna funktion accepterar ett booleskt värde och en celluppsättning av två funktioner. Den första av dessa funktioner utvärderas om det booleska värdet utvärderas som sant, och det andra om det booleska värdet utvärderas som felaktigt. Vi kan enkelt skriva fabriksfunktionen nu:

fac = @(n,f) if_(n>1, {@()n*f(n-1,f), @()1});

Problemet här är att vi inte direkt kan åberopa ett rekursivt samtal, eftersom funktionen ännu inte är tilldelad en variabel när den högra sidan utvärderas. Vi kan dock slutföra detta steg genom att skriva

factorial_ = @(n)fac(n,fac);

Nu @(n)fac(n,fac) den faktiska funktionen rekursivt. Ett annat sätt att göra detta i funktionell programmering med hjälp av en y-kombinator, som också enkelt kan implementeras:

y_ = @(f)@(n)f(n,f);

Med detta verktyg är faktorfunktionen ännu kortare:

factorial_ = y_(fac);

Eller direkt:

factorial_ = y_(@(n,f) if_(n>1, {@()n*f(n-1,f), @()1}));

Spara flera siffror i samma .fig-fil

Genom att sätta flera figurhandtag i en grafikuppsättning kan flera siffror sparas i samma .fig-fil

h(1) = figure;
scatter(rand(1,100),rand(1,100));

h(2) = figure;
scatter(rand(1,100),rand(1,100));

h(3) = figure;
scatter(rand(1,100),rand(1,100));

savefig(h,'ThreeRandomScatterplots.fig');
close(h);

Detta skapar 3 spridplotter av slumpmässiga data, varje del av den grafiska arrayen h. Då kan grafikfältet sparas med hjälp av savefig som med en normal siffra, men med handtaget till grafikfältet som ett extra argument.

En intressant sidoanteckning är att siffrorna tenderar att hålla sig ordnade på samma sätt som de sparades när du öppnar dem.

Kommentarblock

Om du vill kommentera en del av din kod kan kommentarblock vara användbara. Kommentarblocket börjar med %{ i en ny rad och slutar med %} i en annan ny rad:

a = 10;
b = 3;
%{
c = a*b;
d = a-b;
%}

Detta gör att du kan fälla de avsnitt som du kommenterade för att göra koden mer ren och kompakt.

Dessa block är också användbara för att slå på / av delar av din kod. Allt du behöver göra för att avmarkera blocket är att lägga till ytterligare % innan det strats:

a = 10;
b = 3;
%%{ <-- another % over here
c = a*b;
d = a-b;
%}

Ibland vill du kommentera ett avsnitt av koden, men utan att påverka dess intryck:

for k = 1:a
    b = b*k;
    c = c-b;
    d = d*c;
    disp(b)
end

Vanligtvis när du markerar ett kodblock och trycker på Ctrl + r för att kommentera det (genom att lägga till % automatiskt till alla rader, sedan när du trycker på senare Ctrl + i för automatisk indragning, flyttar kodblocket från dess rätta hierarkiska plats och flyttade för mycket till höger:

for k = 1:a
    b = b*k;
    %     c = c-b;
    %     d = d*c;
    disp(b)
end

Ett sätt att lösa detta är att använda kommentarblock, så att den inre delen av blocket förblir korrekt intryckt:

for k = 1:a
    b = b*k;
    %{
    c = c-b;
    d = d*c;
    %}
    disp(b)
end


Modified text is an extract of the original Stack Overflow Documentation
Licensierat under CC BY-SA 3.0
Inte anslutet till Stack Overflow