En ting jeg aldri kunne viklet hodet rundt er hvordan Flatten
utstyrt med en matrise som det andre argumentet, og Mathematica hjelpen er ikke spesielt bra på denne.
Hentet fra Flatten
Mathematica dokumentasjon:
Flatten[list, {{s11, s12, ...}, {s21, s22, ...}, ...}]
Flater
list
ved å kombinere alle nivåer $ s_ {ij} $ for å gjøre hvert nivå $ i $ i resultatet.
Kan noen utdype hva dette egentlig betyr / gjør?
Svar
En praktisk måte å tenke på Flatten
med det andre argumentet er at den utfører noe sånt som Transpose
for raggede (uregelmessige) lister. Her er en enkel eksempel:
In[63]:= Flatten[{{1,2,3},{4,5},{6,7},{8,9,10}},{{2},{1}}] Out[63]= {{1,4,6,8},{2,5,7,9},{3,10}}
Det som skjer er at elementene som utgjør uted nivå 1
i den opprinnelige listen er nå bestanddeler på nivå 2
i resultatet, og omvendt. Dette er nøyaktig hva Transpose
gjør, men gjøres for uregelmessige lister. Vær imidlertid oppmerksom på at noe informasjon om posisjoner går tapt her, så vi kan ikke direkte invertere operasjonen:
In[65]:= Flatten[{{1,4,6,8},{2,5,7,9},{3,10}},{{2},{1}}] Out[65]= {{1,2,3},{4,5,10},{6,7},{8,9}}
For å få den reversert riktig, ville vi ha å gjøre noe som dette:
In[67]:= Flatten/@Flatten[{{1,4,6,8},{2,5,7,9},{3,{},{},10}},{{2},{1}}] Out[67]= {{1,2,3},{4,5},{6,7},{8,9,10}}
Et mer interessant eksempel er når vi har dypere hekking:
In[68]:= Flatten[{{{1,2,3},{4,5}},{{6,7},{8,9,10}}},{{2},{1},{3}}] Out[68]= {{{1,2,3},{6,7}},{{4,5},{8,9,10}}}
Også her kan vi se at Flatten
effektivt fungerte som (generalisert) Transpose
, og byttet ut brikker på de to første nivåene Følgende vil være vanskeligere å forstå:
In[69]:= Flatten[{{{1, 2, 3}, {4, 5}}, {{6, 7}, {8, 9, 10}}}, {{3}, {1}, {2}}] Out[69]= {{{1, 4}, {6, 8}}, {{2, 5}, {7, 9}}, {{3}, {10}}}
Følgende bilde illustrerer dette generaliserte transponert:
Vi kan gjøre det i to påfølgende trinn:
In[72]:= step1 = Flatten[{{{1,2,3},{4,5}},{{6,7},{8,9,10}}},{{1},{3},{2}}] Out[72]= {{{1,4},{2,5},{3}},{{6,8},{7,9},{10}}} In[73]:= step2 = Flatten[step1,{{2},{1},{3}}] Out[73]= {{{1,4},{6,8}},{{2,5},{7,9}},{{3},{10}}}
Siden permutasjonen {3,1,2}
kan fås som {1,3,2}
etterfulgt av {2,1,3}
. En annen måte å se hvordan det fungerer er å bruk tall wh som indikerer posisjonen i listestrukturen:
Flatten[{{{111, 112, 113}, {121, 122}}, {{211, 212}, {221, 222, 223}}}, {{3}, {1}, {2}}] (* ==> {{{111, 121}, {211, 221}}, {{112, 122}, {212, 222}}, {{113}, {223}}} *)
Fra dette kan man se at i den ytterste listen (første nivå), den tredje indeksen (tilsvarende tredje nivå av den opprinnelige listen) vokser, i hver medlemsliste (andre nivå) vokser det første elementet per element (tilsvarer det første nivået av den opprinnelige listen), og til slutt i den innerste (tredje nivå) listene, vokser den andre indeksen , tilsvarende det andre nivået i den opprinnelige listen. Generelt sett, hvis det k-th elementet i listen som er gitt som det andre elementet er {n}
, tilsvarer økning av den k-th indeksen i den resulterende listestrukturen å øke den n-th indeksen i opprinnelig struktur.
Til slutt kan man kombinere flere nivåer for effektivt å flate undernivåene, slik:
In[74]:= Flatten[{{{1,2,3},{4,5}},{{6,7},{8,9,10}}},{{2},{1,3}}] Out[74]= {{1,2,3,6,7},{4,5,8,9,10}}
Kommentarer
Svar
Et annet listeargument til Flatten
serverer to formål. Først spesifiserer den rekkefølgen indeksene skal gjentas når elementer samles. For det andre beskriver den listeflatning i det endelige resultatet. La oss se på hver av disse funksjonene etter tur.
Iterasjonsrekkefølge
Vurder følgende matrise:
$m = Array[Subscript[m, Row[{##}]]&, {4, 3, 2}]; $m // MatrixForm
Vi kan bruke et Table
uttrykk for å lage en kopi av matrisen ved å itere over alle elementene:
$m === Table[$m[[i, j, k]], {i, 1, 4}, {j, 1, 3}, {k, 1, 2}] (* True *)
Denne identiteten operasjonen er uinteressant, men vi kan transformere matrisen ved å bytte rekkefølgen på iterasjonsvariablene. For eksempel kan vi bytte i
og j
iteratorer. Dette tilsvarer bytte av nivå 1 og nivå 2 indekser og deres tilhørende elementer:
$r = Table[$m[[i, j, k]], {j, 1, 3}, {i, 1, 4}, {k, 1, 2}]; $r // MatrixForm
Hvis vi ser nøye på, kan vi se at hvert originale element $m[[i, j, k]]
vil bli funnet å svare til det resulterende elementet $r[[j, i, k]]
– de to første indeksene har bie n «byttet ut».
Flatten
lar oss uttrykke en tilsvarende operasjon til dette Table
uttrykket mer kortfattet: / p>
$r === Flatten[$m, {{2}, {1}, {3}}] (* True *)
Det andre argumentet til Flatten
uttrykk spesifiserer spesifikt ønsket indeksrekkefølge: indeks 1, 2, 3 er endret til å bli indekser 2, 1, 3. Legg merke til hvordan vi ikke trengte å spesifisere et område for hver dimensjon i matrisen – en betydelig notasjonskomfort.
Følgende Flatten
er en identitetsoperasjon siden den ikke spesifiserer noen endring i indeksrekkefølgen:
$m === Flatten[$m, {{1}, {2}, {3}}] (* True *)
Mens følgende uttrykk ordner alle tre indeksene på nytt: 1, 2 , 3 -> 3, 2, 1
Flatten[$m, {{3}, {2}, {1}}] // MatrixForm
Igjen , kan vi bekrefte at et originalt element funnet i indeksen [[i, j, k]]
nå vil bli funnet på [[k, j, i]]
i resultatet.
Hvis noen indekser er utelatt fra en Flatten
uttrykk, de behandles som om de hadde blitt spesifisert sist og i sin naturlige rekkefølge:
Flatten[$m, {{3}}] === Flatten[$m, {{3}, {1}, {2}}] (* True *)
Dette siste eksemplet kan forkortes ytterligere:
Flatten[$m, {3}] === Flatten[$m, {{3}}] (* True *)
En tom indeksliste resulterer i identitetsoperasjonen:
$m === Flatten[$m, {}] === Flatten[$m, {1}] === Flatten[$m, {{1}, {2}, {3}}] (* True *)
Det tar seg av iterasjonsrekkefølge og indeksbytte. La oss se på …
Listeutflatning
Man kan lure på hvorfor vi måtte spesifisere hver indeks i en underliste i de foregående eksemplene. Årsaken er at hver underliste i indeksspesifikasjonen spesifiserer hvilke indekser som skal flates sammen i resultatet. Tenk igjen på følgende identitetsoperasjon:
Flatten[$m, {{1}, {2}, {3}}] // MatrixForm
Hva skjer hvis vi kombinerer de to første indeksene i samme underliste ?
Flatten[$m, {{1, 2}, {3}}] // MatrixForm
Vi kan se at det opprinnelige resultatet var et 4 x 3 rutenett av par, men det andre resultatet er en enkel parliste. Den dypeste strukturen, parene, ble uberørt. De to første nivåene er flatet ut til ett nivå. Parene i det tredje nivået av kilden matrise forble ikke flat.
Vi kunne kombinere de to andre indeksene i stedet:
Flatten[$m, {{1}, {2, 3}}] // MatrixForm
Dette resultatet har samme antall rader som den opprinnelige matrisen, noe som betyr at det første nivået ble uberørt. Men hver resultatrad har en flat liste med seks elementer hentet fra den tilsvarende opprinnelige raden med tre par. Dermed er de to nedre nivåene blitt flatt.
Vi kan også kombinere alle tre indeksene for å få et fullstendig flatt resultat:
Flatten[$m, {{1, 2, 3}}]
Dette kan forkortes:
Flatten[$m, {{1, 2, 3}}] === Flatten[$m, {1, 2, 3}] === Flatten[$m] (* True *)
Flatten
tilbyr også en kort beskrivelse når ingen indeksbytte skal finne sted:
$n = Array[n[##]&, {2, 2, 2, 2, 2}]; Flatten[$n, {{1}, {2}, {3}, {4}, {5}}] === Flatten[$n, 0] (* True *) Flatten[$n, {{1, 2}, {3}, {4}, {5}}] === Flatten[$n, 1] (* True *) Flatten[$n, {{1, 2, 3}, {4}, {5}}] === Flatten[$n, 2] (* True *) Flatten[$n, {{1, 2, 3, 4}, {5}}] === Flatten[$n, 3] (* True *)
«Ragged» Arrays
Alle eksemplene så langt har brukt matriser av forskjellige dimensjoner. Flatten
tilbyr en veldig kraftig funksjon som gjør det til mer enn bare en forkortelse for et Table
-uttrykk. Flatten
vil elegant behandle saken der underlister på et gitt nivå har forskjellige lengder. Manglende elementer blir stille ignorert. For eksempel kan en trekantet matrise vendes:
$t = Array[# Range[#]&, {5}]; $t // TableForm (* 1 2 4 3 6 9 4 8 12 16 5 10 15 20 25 *) Flatten[$t, {{2}, {1}}] // TableForm (* 1 2 3 4 5 4 6 8 10 9 12 15 16 20 25 *)
…eller vendt og flatt:
Flatten[$t, {{2, 1}}] (* {1,2,3,4,5,4,6,8,10,9,12,15,16,20,25} *)
Kommentarer
- Dette er en fantastisk og grundig forklaring!
- @ rm-rf Takk. Jeg regner med at hvis
Flatten
ble generalisert til å akseptere en funksjon som skal brukes når flate (kontraherende) indekser, ville det være en utmerket start på » tensoralgebra i en boks «. - Noen ganger trenger vi å gjøre interne sammentrekninger. Nå vet jeg at jeg kan gjøre det ved å bruke
Flatten[$m, {{1}, {2, 3}}]
i stedet for Map Flatten over et eller annet nivå. Det ville være fint omFlatten
aksepterte negative argumenter for å gjøre det. Så denne saken kan være å skrive somFlatten[$m, -2]
. - Hvorfor dette utmerkede svaret fikk færre stemmer enn Leonid ‘ s: (.
- @Tangshutao Se andre vanlige spørsmål om -profilen .
Svar
Jeg lærte mye av WReachs og Leonids svar, og jeg vil gjerne gi et lite bidrag:
Det virker verdt understreker at den primære hensikten med det listeverdige andre argumentet til Flatten
bare er å flate visse nivåer av lister (som WReach nevner i sin Listeutflatning seksjon). Bruk av Flatten
som en fillete Transpose
virker som en side -effekten av dette primære designet, etter min mening.
For eksempel trengte jeg for eksempel i går denne transformasjonen
lists = { {{{1, 0}, {1, 1}}, {{2, 0}, {2, 4}}, {{3, 0}}}, {{{1, 2}, {1, 3}}, {{2, Sqrt[2]}}, {{3, 4}}} (*, more lists... *) };
til denne:
list2 = { {{1, 0}, {1, 1}, {2, 0}, {2, 4}, {3, 0}}, {{1, 2}, {1, 3}, {2, Sqrt[2]}, {3, 4}} (*, more lists... *) }
Det vil si at jeg trengte å knuse andre og tredje listenivå sammen.
Jeg gjorde det med
list2 = Flatten[lists, {{1}, {2, 3}}];
Svar
Dette er et gammelt spørsmål, men ofte spurt av et parti av mennesker. I dag da jeg prøvde å forklare hvordan dette fungerer, kom jeg over en ganske klar forklaring, så jeg tror det å dele det her vil være nyttig for videre publikum.
Hva betyr indeks?
La oss først gjøre klart hva indeks : I Mathematica er hvert uttrykk et tre, for eksempel, la oss se på en liste:
TreeForm@{{1,2},{3,4}}
Hvordan navigerer du i et tre?
Enkelt! Du starter fra roten og velger ved hver kryssing hvilken vei du vil gå, for eksempel her hvis du vil nå 2
, begynner du med å velge først bane, velg deretter andre bane. La oss skrive det ut som {1,2}
som er bare indeksen til elementet 2
i dette uttrykket.
Hvordan forstå Flatten
?
Her bør du vurdere et enkelt spørsmål hvis jeg ikke gir deg et fullstendig uttrykk, men i stedet gir jeg deg alle elementene og deres indekser, hvordan konstruerer du det originale uttrykket? Her gir jeg deg for eksempel:
{<|"index" -> {1, 1}, "value" -> 1|>, <|"index" -> {1, 2}, "value" -> 2|>, <|"index" -> {2, 1}, "value" -> 3|>, <|"index" -> {2, 2}, "value" -> 4|>}
og forteller deg at alle hoder er List
, så hva er det det opprinnelige uttrykket?
Vel, du kan sikkert rekonstruere det opprinnelige uttrykket som {{1,2},{3,4}}
, men hvordan? Du kan sannsynligvis liste følgende trinn:
- Først ser vi på det første elementet i indeksen og sorterer og samler etter det. Så vet vi at første element i hele uttrykket skal inneholde de to første elementene i den opprinnelige listen …
- Så fortsetter vi å se på det andre argumentet, gjør det samme …
- Endelig får vi den opprinnelige listen som
{{1,2},{3,4}}
.
Vel, det er rimelig! Så hva om jeg sier deg, nei, du bør først sortere og samle etter det andre elementet i indeksen og deretter samle etter det første elementet i indeksen? Eller jeg sier at vi ikke samler dem to ganger, vi sorterer bare etter begge elementene, men gir det første argumentet høyere prioritet?
Vel, du vil sannsynligvis få de følgende to listene, ikke sant?
-
{{1,3},{2,4}}
-
{1,2,3,4}
Vel, sjekk selv, Flatten[{{1,2},{3,4}},{{2},{1}}]
og Flatten[{{1,2},{3,4}},{{1,2}}]
gjør det samme!
Så hvordan du forstår det andre argumentet til Flatten ?
- Hvert listeelement i hovedlisten, for eksempel
{1,2}
, betyr at du bør GATHER alle listene i henhold til disse elementene i indeksen, med andre ord disse nivåer . - Bestillingen inne i et listeelement representerer hvordan du SORT elementene samlet i en liste i forrige trinn . for eksempel betyr
{2,1}
at posisjonen på andre nivå har høyere prioritet enn posisjonen på første nivå.
Eksempler
La oss nå ha litt øvelse for å bli kjent med tidligere regler.
1. Transpose
Målet med Transpose
på en enkel m * n-matrise er å lage $ A_ {i, j} \ rightarrow A ^ T_ {j, i} $. Men vi kan vurdere det på en annen måte, opprinnelig sorterer vi element etter deres i
indeks først, og deretter sortere dem etter j
indeksen. Nå trenger vi bare å endre for å sortere dem etter j
indeks først og deretter med i
neste! Så koden blir:
Flatten[mat,{{2},{1}}]
Enkelt, ikke sant?
2. Tradisjonelt Flatten
Målet med tradisjonell flatning på en enkel m * n-matrise er å lag en 1D-matrise i stedet for en 2D-matrise, for eksempel: Flatten[{{1,2},{3,4}}]
returnerer {1,2,3,4}
. Dette betyr at vi ikke «t samler elementer denne gangen, vi bare sorter dem, først etter deres første indeks og deretter med den andre:
Flatten[mat,{{1,2}}]
3. ArrayFlatten
La oss diskutere et mest enkelt tilfelle av ArrayFlatten, her har vi en 4D-liste:
{{{{1,2},{5,6}},{{3,4},{7,8}}},{{{9,10},{13,14}},{{11,12},{15,16}}}}
så hvordan kan vi gjøre en slik konvertering for å gjøre det til en 2D-liste?
$ \ left (\ begin {array} {cc} \ left (\ begin {array} {cc} 1 & 2 \\ 5 & 6 \\ \ end {array} \ right) & \ venstre (\ begin {array} {cc} 3 & 4 \\ 7 & 8 \\ \ end {array} \ høyre) \\ \ left (\ begin {array} {cc} 9 & 10 \\ 13 & 14 \\ \ end {array} \ høyre) & \ left (\ begin {array} {cc} 11 & 12 \\ 15 & 16 \\ \ end {array} \ right) \\ \ end {array} \ right) \ rightarrow \ left (\ begin {array} {cccc} 1 & 2 & 3 & 4 \\ 5 & 6 & 7 & 8 \\ 9 & 10 & 11 & 12 \\ 13 & 14 & 15 & 16 \\ \ end {array} \ right) $
Vel, dette er også enkelt, vi trenger gruppen etter den opprinnelige første og tredje nivåindeksen først, og vi bør gi den første indeksen høyere prioritet i sortering. Det samme gjelder andre og fjerde nivå:
Flatten[mat,{{1,3},{2,4}}]
4. «Endre størrelse» på et bilde
Nå har vi et bilde, for eksempel:
img=Image@RandomReal[1,{10,10}]
Men det er definitivt for lite til at vi kan visning, så vi vil gjøre den større ved å utvide hver piksel til en stor piksel på 10 * 10 størrelse.
Først skal vi prøve:
ConstantArray[ImageData@img,{10,10}]
Men den returnerer en 4D-matrise med dimensjonene {10,10,10,10}. Så vi bør Flatten
den. Denne gangen vil vi at det tredje argumentet i stedet skal ha høyere prioritet av den første, så en mindre innstilling ville fungere:
Image@Flatten[ConstantArray[ImageData@img,{10,10}],{{3,1},{4,2}}]
En sammenligning:
Håper dette kan hjelpe!
Flatten[{{{111, 112, 113}, {121, 122}}, {{211, 212}, {{221,222,223}}}, {{3},{1},{2}}}
og resultatet ville lese{{{111, 121}, {211, 221}}, {{112, 122}, {212, 222}}, {{113}, {223}}}
.In[63]:= Flatten[{{1,2,3},{4,5},{6,7},{8,9,10}},{{2},{1}}] Out[63]= {{1,4,6,8},{2,5,7,9},{3,10}}
sier du Det som skjer er at elementene som utgjorde nivå 1 i den opprinnelige listen, nå er bestanddeler på nivå 2 i resultatet. Jeg forstår ikke ‘, input og output har samme nivåstruktur, elementene er fortsatt på samme nivå. Kan du forklare dette i det store og hele?