Dag: 6
Språk: Dyalog APL
Ganska kort och enkel uppgift så jag passade på att skriva en lite längre detaljerad beskrivning av hur APL koden fungerar. Uppdaterade även dag 4 med en kortare lösning. Finns även en beskrivning av hur den koden fungerar.
4 14{1-⍨⍺+⍸<\⍺=≢¨⍺∪/⍵}¨⊃⎕NGET'6.txt'1
Beskrivning:
APL interpreteras från höger till vänster. Går att köra koden online på https://tryapl.org
4 14{1-⍨⍺+⍸<\⍺=≢¨⍺∪/⍵}¨⊃⎕NGET'6.txt'1
⊃⎕NGET'6.txt'1
Läser in filen och plockar ut första elementet som är innehållet i filen. Resultatet är en array innehållande en textarray. Resten av beskrivningen kommer använda testdata istället för att kunna visa kortare output från dyalog.
test←⊂'bvwbjplbgvbhsrlpgdmjqwftvncz'
test
┌────────────────────────────┐
│bvwbjplbgvbhsrlpgdmjqwftvncz│
└────────────────────────────┘
4 14{1-⍨⍺+⍸<\⍺=≢¨⍺∪/⍵}¨test
┌─┬──┐
│5│23│
└─┴──┘
{1-⍨⍺+⍸<\⍺=≢¨⍺∪/⍵}
En dfn eller anonym funktion. Funktioner i apl kan ta en (monadisk) eller två (dyadisk) arrayer som argument. Monadiska funktioner har argumentet till höger (f Y) och dyadiska har argument på båda sidorna (X f Y). { } används för att skapa en dfn. För att komma åt argumenten till funktionen använder man ⍺ - alpha för vänster argument och ⍵ - omega för höger argument. X {⍺ ⍵} Y är alltså samma sak som att skriva X Y. 1 {⍺+⍵+⍺+⍵} 2 blir 1 + 2 + 1 + 2.
4 14{⍺∪/⍵}¨test
┌────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┬───────────────────────────────────────···
│┌───┬────┬────┬────┬────┬────┬────┬───┬────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬────┐│┌──────────┬──────────┬──────────┬─────···
││bvw│vwbj│wbjp│bjpl│jplb│plbg│lbgv│bgv│gvbh│vbhs│bhsr│hsrl│srlp│rlpg│lpgd│pgdm│gdmj│dmjq│mjqw│jqwf│qwft│wftv│ftvn│tvnc│vncz│││bvwjplghsr│vwbjplghsr│wbjplgvhsr│bjplg···
│└───┴────┴────┴────┴────┴────┴────┴───┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┘│└──────────┴──────────┴──────────┴─────···
└────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┴───────────────────────────────────────···
f / X är en operatör. Operatörer i apl tar andra funktioner som argument. De finns i både monadisk och dyadisk form. Monadiska operatörer tar funktionen som vänster argument. f/ "reduce" är samma sak som reduce/foldr/foldRight i andra språk. +/1 2 3 4 = 1+2+3+4 = 10. f / X "reduce" kan även modifieras med ytterligare ett argument till vänster Is f / X för att få funktionen n-wise reduce (windowed/sliding reduce). Is anger storleken på fönstret. 2+/1 2 3 4 (parvis) = 1+2 2+3 3+4 = 3 5 7.
∪ Y "unique" plockar ut de unika elementen ur arrayen Y. ∪'aabccc' = 'abc'
{⍺∪/⍵} är en funktion som kör unique på fönster av storlek ⍺ (vänster argument) element på arrayen ⍵ (höger argument).
4 14{≢¨⍺∪/⍵}¨test
┌─────────────────────────────────────────────────┬───────────────────────────────────────────┐
│3 4 4 4 4 4 4 3 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4│10 10 10 9 10 10 11 12 13 14 14 14 14 14 14│
└─────────────────────────────────────────────────┴───────────────────────────────────────────┘
≢ 'tally" antalet element i vektorn. ≢'abcd' = 4
4 14{⍺=≢¨⍺∪/⍵}¨test
┌─────────────────────────────────────────────────┬─────────────────────────────┐
│0 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1│0 0 0 0 0 0 0 0 0 1 1 1 1 1 1│
└─────────────────────────────────────────────────┴─────────────────────────────┘
Vilka element har samma storlek som den valda fönsterstorleken. apl använder 1/0 som true/false
4 14{<\⍺=≢¨⍺∪/⍵}¨test
┌─────────────────────────────────────────────────┬─────────────────────────────┐
│0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0│0 0 0 0 0 0 0 0 0 1 0 0 0 0 0│
└─────────────────────────────────────────────────┴─────────────────────────────┘
Bara det första sanna värdet som är intressant.
f\Y "Scan" ytterligare en operatör. ungefär samma som scanl/scanLeft i andra språk. <\Y kör en scan med "less than" som funktion på arrayen Y. Resultatet blir lite annorlunda än i andra språk när man använder en icke-associativ funktion eftersom apl tolkas från höger till vänster. <\0 1 0 1= (0) (0<1) (0<(1 <0)) (0<(1<(0<1))) = 0 1 0 0.
4 14{⍸<\⍺=≢¨⍺∪/⍵}¨test
┌─┬──┐
│2│10│
└─┴──┘
⍸ Y "where" om Y är en boolesk array får man tillbaka en array innehållande alla index satta till 1 (true) ⍸1 0 1 0 = 1 3
4 14{⍺+⍸<\⍺=≢¨⍺∪/⍵}¨test
┌─┬──┐
│6│24│
└─┴──┘
Eftersom man vill ha fram index efter markören behöver man addera fönsterstorleken ⍺.
4 14{1-⍨⍺+⍸<\⍺=≢¨⍺∪/⍵}¨test
┌─┬──┐
│5│23│
└─┴──┘
-1 för att korrigera off-by-1 fel. APL använder som standard 1 som startindex. (går att ändra till 0, ⎕IO←0)
X f⍨ Y "commute" är en operatör som byter plats på argumenten till funktionen. X f⍨ Y = Y f X.
APL tolkas från höger till vänster. 6+4-1 = 6+(4-1), 6+4÷2 = 6+(4÷2). För att slippa skriva parenteser (6+4)-1, (6+4)÷2 så kan man byta plats på argumenten 6+4-1 = 1-⍨6+4, 6+4÷2 = 2÷⍨6+4.
Går att skriva om 1-⍨ till ¯1+ (addera -1) om man föredrar den stilen.