Yksi asia, jota en koskaan voinut kietoa pääni ympärille, on se, miten Flatten toimii, kun toimitetaan matriisina toisena argumenttina, ja Mathematica -ohje ei ole erityisen hyvä tässä.

Otettu kohteesta Flatten Mathematica -dokumentaatio:

Flatten[list, {{s11, s12, ...}, {s21, s22, ...}, ...}] 

Tasoittaa list yhdistämällä kaikki tasot $ s_ {ij} $, jotta jokaisesta tasosta muodostuu tulos. $

”62665b34cf”>

Voisiko joku kertoa tarkemmin, mitä tämä todella tarkoittaa / tarkoittaa?

Vastaa

Yksi kätevä tapa ajatella Flatten toisella argumentilla on se, että se suorittaa jotain Transpose -tapaa repaleille (epäsäännöllisille) luetteloille. Tässä on yksinkertainen esimerkki:

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

Tapahtuu, että elementit muodostavat Alkuperäisen luettelon uted-taso 1 ovat nyt komponentteja tasolla 2 tuloksessa ja päinvastoin. Tätä Transpose tekee, mutta epäsäännöllisille luetteloille. Huomaa kuitenkin, että osa sijainneista häviää täällä, joten emme voi suoraan kääntää operaatiota:

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

Jotta se voidaan kääntää oikein, meillä on tehdä jotain tällaista:

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

Mielenkiintoisempi esimerkki on, kun pesimme syvemmällä:

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

Tässä voimme jälleen nähdä, että Flatten toimi tehokkaasti kuten (yleistetty) Transpose, vaihtamalla kappaleita kahdella ensimmäisellä tasolla Seuraavaa on vaikeampaa ymmärtää:

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

Seuraava kuva kuvaa tätä yleistettyä siirtoa:

Kuva syklisestä yleistetystä transponoinnista

Voimme tehdä sen kahdessa peräkkäisessä vaiheessa:

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

Koska permutaatio {3,1,2} voidaan saada nimellä {1,3,2} ja sen jälkeen {2,1,3}. Toinen tapa nähdä, miten se toimii, on käytä numeroita wh ich ilmaisee sijainnin luettelorakenteessa:

Flatten[{{{111, 112, 113}, {121, 122}}, {{211, 212}, {221, 222, 223}}}, {{3}, {1}, {2}}] (* ==> {{{111, 121}, {211, 221}}, {{112, 122}, {212, 222}}, {{113}, {223}}} *) 

Tästä voidaan nähdä, että syrjäisimmässä luettelossa (ensimmäinen taso), kolmas hakemisto (vastaa alkuperäisen luettelon kolmas taso) kasvaa, jokaisessa jäsenluettelossa (toinen taso) ensimmäinen elementti kasvaa elementtiä kohti (vastaa alkuperäisen luettelon ensimmäistä tasoa) ja lopuksi sisimmissä (kolmas taso) luetteloissa toinen indeksi kasvaa , joka vastaa alkuperäisen luettelon toista tasoa. Yleensä jos toisena elementtinä läpäistyn luettelon k: s elementti on {n}, k: nnen indeksin kasvattaminen tuloksena olevassa luettelorakenteessa vastaa n: nnen indeksin kasvua alkuperäinen rakenne.

Lopuksi voidaan yhdistää useita tasoja tasoittamaan alatasoja tehokkaasti, kuten näin:

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

Kommentit

  • Minusta on ’ helpompi ymmärtää, jos numerot osoittavat alkuperäisen sijainnin sisäkkäisluettelossa. Esimerkiksi kolmen numeron permutaatioesimerkissä se olisi Flatten[{{{111, 112, 113}, {121, 122}}, {{211, 212}, {{221,222,223}}}, {{3},{1},{2}}} ja tulos olisi {{{111, 121}, {211, 221}}, {{112, 122}, {212, 222}}, {{113}, {223}}}.
  • @celtschk Kiitos, mutta en ole vakuuttunut. Minulle henkilökohtaisesti on helpompaa seurata visuaalisesti erillisiä lukuja ja nähdä, mihin ne uudessa rakenteessa päätyvät. Mutta lisää tämä vapaasti vastaukseeni, tämä on minulle täysin sopiva.
  • Luulen, että ymmärrystapamme ovat vain erilaiset tältä osin. Oikeastaan vasta kirjoitettuani tietoni ymmärsin täysin syklisen permutaation (mutta sitten suoraan, ilman jälkikäteen tekemääsi kaksivaiheista hajotusta). Asia on, että tällä tavalla näet heti, mikä hakemisto muuttuu, kun siirryt jokaisella listalla, ja voit määrittää, mistä numero on peräisin luettelorakenteesta edes katsomatta alkuperäistä luetteloa. Toisin sanoen, se paljastaa suoremmin (ainakin minulle) muutoksen rakenteen .
  • @celtschk Kyllä, ymmärsin perustelut. Mutta minulle oli helpompaa ymmärtää, mitkä elementit hyppäsivät luetteloista, sen sijaan että tarkasteltaisiin elementtejä ’. Voi olla se ’ vain minä, olen aina pyrkinyt geometriaan eikä algebraan. Luulen, että molemmilla tavoilla on omat etunsa.
  • @LeonidShifrin 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}} -sivustolle sanot Mitä tapahtuu, elementit, jotka olivat alkuperäisen luettelon tason 1, ovat nyt komponentteja tason 2 tulos. En ’ ymmärrä oikein, syötteillä ja tuotoksilla on sama tasorakenne, elementit ovat edelleen samalla tasolla.Voitteko selittää tämän yleisesti?

vastaus

Toinen luetteloargumentti ryhmälle Flatten palvelee kahta tarkoituksiin. Ensinnäkin se määrittää järjestyksen, jossa indeksit toistetaan elementtejä kerättäessä. Toiseksi se kuvaa luettelon litistämistä lopputuloksessa. Tarkastellaan kutakin näistä ominaisuuksista vuorotellen.

Kordausjärjestys

Harkitse seuraavaa matriisia:

$m = Array[Subscript[m, Row[{##}]]&, {4, 3, 2}]; $m // MatrixForm 

matriisitulos

Voimme käyttää Table -lausekkeen avulla voit luoda kopion matriisista iteroimalla kaikki sen elementit:

$m === Table[$m[[i, j, k]], {i, 1, 4}, {j, 1, 3}, {k, 1, 2}] (* True *) 

Tämä identiteetti toiminta ei ole mielenkiintoista, mutta voimme muuttaa taulukon vaihtamalla iteraatiomuuttujien järjestyksen. Esimerkiksi voimme vaihtaa i ja j iteraattorit. Tämä tarkoittaa tason 1 ja 2 indeksien ja niitä vastaavien elementtien vaihtamista:

$r = Table[$m[[i, j, k]], {j, 1, 3}, {i, 1, 4}, {k, 1, 2}]; $r // MatrixForm 

matriisitulos

Jos katsomme tarkkaan, voimme nähdä, että jokaisen alkuperäisen elementin $m[[i, j, k]] havaitaan vastaavan syntynyttä elementtiä $r[[j, i, k]] – kahdella ensimmäisellä indeksillä on mehiläinen n ”vaihdettu”.

Flatten antaa meille mahdollisuuden ilmaista vastaavampi operaatio tälle lausekkeelle Table:

$r === Flatten[$m, {{2}, {1}, {3}}] (* True *) 

Lausekkeen Flatten toinen argumentti määrittää nimenomaisesti halutun hakemistojärjestyksen: indeksit 1, 2, 3 ovat muutettu indeksiksi 2, 1, 3. Huomaa, kuinka meidän ei tarvinnut määrittää aluetta taulukon kullekin ulottuvuudelle – merkittävä notaatiomukavuus.

Seuraava Flatten on identiteettitoiminto, koska siinä ei määritetä muutoksia hakemistojärjestykseen:

$m === Flatten[$m, {{1}, {2}, {3}}] (* True *) 

Seuraava lauseke järjestää kaikki kolme indeksiä uudelleen: 1, 2 , 3 -> 3, 2, 1

Flatten[$m, {{3}, {2}, {1}}] // MatrixForm 

matriisitulos

Jälleen , voimme varmistaa, että hakemistosta [[i, j, k]] löydetty alkuperäinen elementti löytyy nyt tuloksesta osoitteesta [[k, j, i]].

Jos Flatten lauseketta, niitä kohdellaan ikään kuin ne olisi määritelty viimeisenä ja luonnollisessa järjestyksessä:

Flatten[$m, {{3}}] === Flatten[$m, {{3}, {1}, {2}}] (* True *) 

Tämä viimeinen esimerkki voi lyhennetään vielä tarkemmin:

Flatten[$m, {3}] === Flatten[$m, {{3}}] (* True *) 

Tyhjä hakemistoluettelo johtaa identiteettioperaatioon:

$m === Flatten[$m, {}] === Flatten[$m, {1}] === Flatten[$m, {{1}, {2}, {3}}] (* True *) 

Se huolehtii iterointijärjestyksestä ja indeksinvaihdosta. Katsotaan nyt seuraavaa …

Luettelon litistäminen

Saattaa ihmetellä, miksi meidän oli määritettävä kukin hakemisto alaluettelosta edellisissä esimerkeissä. Syynä on se, että kukin hakemistomäärittelyn alaluettelo määrittää, mitkä indeksit on tasoitettava yhteen tuloksessa. Harkitse uudelleen seuraavaa identiteettioperaatiota:

Flatten[$m, {{1}, {2}, {3}}] // MatrixForm 

matriisitulos

Mitä tapahtuu, jos yhdistämme kaksi ensimmäistä indeksiä samaan aliluetteloon ?

Flatten[$m, {{1, 2}, {3}}] // MatrixForm 

matriisitulos

Voimme nähdä, että alkuperäinen tulos oli 4 x 3 pariruudukko, mutta toinen tulos on yksinkertainen luettelo pareista. Syvin rakenne, parit, jätettiin koskematta. Kaksi ensimmäistä tasoa on litistetty yhdeksi tasoksi. Lähteen kolmannen tason parit matriisi pysyi litistämättömänä.

Voisimme yhdistää sen sijaan kaksi toista indeksiä:

Flatten[$m, {{1}, {2, 3}}] // MatrixForm 

matriisitulos

Tällä tuloksella on sama määrä rivejä kuin alkuperäisellä matriisilla, mikä tarkoittaa, että ensimmäinen taso jätettiin koskematta. Mutta jokaisella tulosrivillä on tasainen luettelo kuudesta elementistä, jotka on otettu vastaavasta alkuperäisestä kolmen parin rivistä. Siksi kaksi alinta tasoa on litistetty.

Voimme myös yhdistää kaikki kolme indeksiä saadaksesi täysin litistyneen tuloksen:

Flatten[$m, {{1, 2, 3}}] 

matriisitulos

Tämä voidaan lyhentää:

Flatten[$m, {{1, 2, 3}}] === Flatten[$m, {1, 2, 3}] === Flatten[$m] (* True *) 

Flatten tarjoaa myös lyhenteen merkinnän, kun hakemistonvaihtoa ei tapahdu:

$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” -taulukot

Kaikissa tähänastisissa esimerkeissä on käytetty eri ulottuvuuksien matriiseja. Flatten tarjoaa erittäin tehokkaan ominaisuuden, joka tekee siitä muutakin kuin lyhenteen Table -lausekkeesta. Flatten käsittelee sulavasti tapausta, jossa tietyn tason alaluetteloiden pituus on erilainen. Puuttuvat elementit ohitetaan hiljaa. Esimerkiksi kolmion muotoinen taulukko voidaan kääntää:

$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 *) 

…tai käännetty ja litistetty:

Flatten[$t, {{2, 1}}] (* {1,2,3,4,5,4,6,8,10,9,12,15,16,20,25} *) 

kommentit

  • Tämä on upea ja perusteellinen selitys!
  • @ rm-rf Kiitos. Luulen, että jos Flatten yleistettäisiin hyväksymään funktio, jota sovellettaisiin indeksejä litistettäessä, se olisi erinomainen alku ” tensori-algebra tölkissä ”.
  • Joskus meidän on tehtävä sisäisiä supistuksia. Nyt tiedän, että voin tehdä sen käyttämällä Flatten[$m, {{1}, {2, 3}}] -toimintoa Map Flatten -toiminnon sijaan jollain tasolla. Olisi mukavaa, jos Flatten hyväksyisi negatiiviset argumentit. Joten tämä tapaus voidaan kirjoittaa kuten Flatten[$m, -2].
  • Miksi tämä erinomainen vastaus sai vähemmän ääniä kuin Leonid ’ s: (.
  • @Tangshutao Katso toinen UKK-profiili -profiilissani .

Vastaus

Olen oppinut paljon WReachin ja Leonidin vastauksista ja haluaisin antaa pienen panoksen:

Vaikuttaa arvoiselta korostamalla, että luetteloarvoisen Flatten-argumentin ensisijainen tarkoitus on vain tasoittaa tiettyjä luettelotasoja (kuten WReach mainitsee Luettelon litistäminen -osio). Flatten: n käyttäminen räikeänä Transpose näyttää puolelta mielestäni tämän ensisijaisen suunnittelun vaikutus.

Esimerkiksi eilen minun piti muuttaa tätä luetteloa

lists = { {{{1, 0}, {1, 1}}, {{2, 0}, {2, 4}}, {{3, 0}}}, {{{1, 2}, {1, 3}}, {{2, Sqrt[2]}}, {{3, 4}}} (*, more lists... *) }; 

puun muoto1

tähän:

list2 = { {{1, 0}, {1, 1}, {2, 0}, {2, 4}, {3, 0}}, {{1, 2}, {1, 3}, {2, Sqrt[2]}, {3, 4}} (*, more lists... *) } 

puun muoto2

Eli minun täytyi murskata toinen ja kolmas luettelotaso yhteen.

Tein sen

list2 = Flatten[lists, {{1}, {2, 3}}]; 

vastaus

Tämä on vanha kysymys, mutta usein kysyy erä ihmisiä. Tänään, kun yritin selittää, miten tämä toimii, törmäsin melko selkeään selitykseen, joten mielestäni sen jakamisesta täällä olisi hyötyä uudelle yleisölle.

Mitä indeksi tarkoittaa?

Anna ensin selventää mikä index on: Mathematicassa jokainen lauseke on puu, esimerkiksi luettelossa:

TreeForm@{{1,2},{3,4}} 

illus1

Kuinka navigoit puussa?

Yksinkertainen! Aloitat juuresta ja valitset jokaisella risteyksellä, minkä tien mennä, esimerkiksi täällä, jos haluat päästä 2, aloitat valitsemalla ensimmäinen polku ja valitse sitten toinen polku. Kirjoitetaan ”s” se nimellä {1,2}, joka on vain lausekkeen elementti 2 tässä lausekkeessa.

Kuinka ymmärtää Flatten?

Harkitse tässä yksinkertaista kysymystä, jos en anna sinulle täydellistä lauseketta, mutta sen sijaan annan sinulle kaikki elementit ja heidän hakemistonsa, miten rakennat alkuperäisen lausekkeen? Esimerkiksi tässä annan sinulle:

{<|"index" -> {1, 1}, "value" -> 1|>, <|"index" -> {1, 2}, "value" -> 2|>, <|"index" -> {2, 1}, "value" -> 3|>, <|"index" -> {2, 2}, "value" -> 4|>} 

ja sanon, että kaikki päät ovat List, niin mitä ”s alkuperäinen lauseke?

No, varmasti voit rekonstruoida alkuperäisen lausekkeen nimellä {{1,2},{3,4}}, mutta miten? Luultavasti voit luetella seuraavat vaiheet:

  1. Tarkastellaan ensin indeksin ensimmäistä elementtiä ja lajitellaan ja kerätään sen mukaan. Sitten tiedämme, että ensimmäinen koko lausekkeen elementin tulisi sisältää kaksi ensimmäistä -elementtiä alkuperäisessä luettelossa …
  2. Sitten jatkamme toisen argumentin tarkastelua, tee sama …
  3. Lopuksi saamme alkuperäisen luettelon nimellä {{1,2},{3,4}}.

No, se on järkevää! Joten mitä jos sanon sinulle, ei, sinun pitäisi ensin lajitella ja kerätä indeksin toisen elementin mukaan ja sitten kerätä indeksin ensimmäisen elementin mukaan? Tai sanon, että emme kerää niitä kahdesti, me vain lajittelemme molemmat elementit, mutta annamme ensimmäiselle argumentille korkeamman prioriteetin?

No, saatat todennäköisesti saada seuraavat kaksi luetteloa, eikö?

  1. {{1,3},{2,4}}
  2. {1,2,3,4}

No, tarkista itse, Flatten[{{1,2},{3,4}},{{2},{1}}] ja Flatten[{{1,2},{3,4}},{{1,2}}] tee sama!

Joten ymmärrät Flattenin toisen argumentin ?

  1. Jokainen pääluettelon sisältämä luetteloelementti, esimerkiksi {1,2}, tarkoittaa, että sinun pitäisi GATHER kaikki luettelot näiden hakemistossa olevien elementtien mukaan, toisin sanoen nämä tasot .
  2. Listaelementin sisäinen järjestys edustaa sitä, miten LAJITTELET edellisessä vaiheessa luetteloon kerätyt elementit . esimerkiksi {2,1} tarkoittaa, että toisen tason sijainnilla on korkeampi prioriteetti kuin ensimmäisen tason sijainnilla.

Esimerkkejä

Olkoon nyt jonkin verran käytäntöä tuntemaan aiemmat säännöt.

1. Transpose

Transpose yksinkertaisella m * n -matriisilla on tehdä $ A_ {i, j} \ rightarrow A ^ T_ {j, i} $. Mutta voimme pitää sitä toisella tavalla, alun perin lajittelemme elementti i -hakemistonsa mukaan ja lajitellaan ensin niiden j -hakemiston mukaan, nyt meidän on muutettava vain lajittelemaan ne j indeksoi ensin ja sitten i seuraavaksi! Koodista tulee siis:

Flatten[mat,{{2},{1}}] 

Yksinkertainen, eikö?

2. Perinteinen Flatten

Perinteisen litistämisen tavoite yksinkertaisella m * n -matriisilla on luo 1D-matriisi 2D-matriisin sijaan, esimerkiksi: Flatten[{{1,2},{3,4}}] palauttaa {1,2,3,4}. Tämä tarkoittaa, että emme tällä kertaa ”t kerää -elementtejä, vain lajittele ne ensin ensimmäisen hakemistonsa ja sitten toisen mukaan:

Flatten[mat,{{1,2}}] 

3. ArrayFlatten

Tarkastellaan yksinkertaista ArrayFlatten-tapausta, tässä on 4D-luettelo:

{{{{1,2},{5,6}},{{3,4},{7,8}}},{{{9,10},{13,14}},{{11,12},{15,16}}}} 

niin miten voimme tehdä tällaisen muunnoksen, jotta siitä tulisi 2D-luettelo?

$ \ left (\ begin {array} {cc} \ left (\ begin {array} {cc} 1 & 2 \\ 5 & 6 \\ \ end {array} \ right) & \ vasen (\ begin {array} {cc} 3 & 4 \\ 7 & 8 \\ \ end {array} \ right) \\ \ left (\ begin {array} {cc} 9 & 10 \\ 13 & 14 \\ \ end {array} \ oikea) & \ 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) $

No, tämä on myös yksinkertaista, tarvitsemme ensin ryhmän alkuperäisen ensimmäisen ja kolmannen tason indeksin mukaan, ja meidän pitäisi antaa ensimmäiselle indeksille korkeampi prioriteetti lajittelu. Sama pätee toiseen ja neljänteen tasoon:

Flatten[mat,{{1,3},{2,4}}] 

4. ”Muuta kuvan kokoa”

Nyt meillä on kuva, esimerkiksi:

img=Image@RandomReal[1,{10,10}] 

Mutta se on ehdottomasti liian pieni, jotta voimme näkymää, joten haluamme tehdä siitä suuremman laajentamalla jokaisen pikselin 10 * 10 -kokoiseksi valtavaksi pikseliksi.

Yritämme ensin:

ConstantArray[ImageData@img,{10,10}] 

Mutta se palauttaa 4D-matriisin, jonka mitat ovat {10,10,10,10}. Meidän pitäisi siis Flatten se. Tällä kertaa haluamme kolmannen argumentin olevan korkeampi prioriteetti ensimmäisestä, joten pieni viritys toimisi:

Image@Flatten[ConstantArray[ImageData@img,{10,10}],{{3,1},{4,2}}] 

Vertailu:

illus2

Toivottavasti tämä voi auttaa!

Vastaa

Sähköpostiosoitettasi ei julkaista. Pakolliset kentät on merkitty *