Coffeescript / natural sort

 ( log69 | 2017. november 13., hétfő - 0:23 )

Ezen bejegyzés alapján megírtam Ruby mintájára a CS verziót is a természetes sorba rendezésre. Trükkös volt kicsit.

Bemenet egy tömb, melynek elemeit úgy rendezi sorba, hogy a sorba rendezendő szöveget további elemeire bontja szöveget szövegnek, számot pedig számnak értelmezve, figyelmen kívül hagyva a white space-t. Ennek eredményeként az alábbi igaz lesz:

" hello 3 " < " hello 11 "

Cél hogy ne számítson hogy hol mennyi white space van, illetve hogy a számokat számként hasonlítsa össze, és így a 11 nem kerül a 3 elé.

Rövid forráskód | CS tömb metódusok | Teszt kód

Hozzászólás megjelenítési lehetőségek

A választott hozzászólás megjelenítési mód a „Beállítás” gombbal rögzíthető.

Egy hülye kérdés:

lx = x.length; ly = y.length
le = if lx > ly then ly else lx

Csak emiatt az egy összehasonlítás miatt van értelme a hosszt külön változóba kiszedni?

Sőt, ezt az egészet írhatta volna úgy is, hogy le = Math.min(x.length, y.length);

Még nem optimalizáltam a kódot. A helyesség vizsgálatért beszédesebbre írtam, illetve folyamatosan változtattam az algo-t. Ez előtti verzióban felhasználtam lx és ly értékét. Valszeg több mindent lehet optimalizálni.

Annak mi értelme van, hogy ha z1 vagy z2 típusa közül valamelyik string, akkor meghívod mindkettőre a toStringet()?

Nem úgy kéne, hogy ha valamelyiknek a típusa nem string, akkor azt stringgé alakítod toString()-gel? Nekem így tűnne értelmesebbnek.

A legegyszerűbb, if nélküli típusátalakítás stringgé nem az lenne, hogy konkatenálod az üres stringgel? "" + z1 például.

"A legegyszerűbb, if nélküli típusátalakítás stringgé nem az lenne, hogy konkatenálod az üres stringgel? "" + z1 például."

Miért konkatenálnál toString helyett?

Nem kell típusvizsgálat, nincs if, minden beépített típusra és értékre (pl. undefined vagy null) működik.

Nem, egy kicsit trükkösebb. Ugye úgy tud működni a natsort, hogy a tömb elemeit tovább darabolom split-tel és ezen tömböket hasonlítom egymáshoz. Fontos hogy string-et string-gel, number-t number-rel hasonlítsak. Viszont lehet olyan kombináció, hogy string-et number-rel kell hasonlítanom. Ez JS-ben nem működik jól, ezért stringgé kell konvertálnom a number-t. De csak akkor, ha különbözik a típusuk.

Vagyis ha a típusuk különbözik, akkor mindkettőt string-gé konvertálom. Például:

["    hello   3   "] -> ["hello", 3]
["   hello      11  "] -> ["hello", 11]
["  2    world   "] -> [2, "world"]

? "hello" = "hello"
? 3 < 11
? "hello" > "2"  <- ha itt nem string áll, akkor mindig false

Nyilván akkor nem kellene a toString() ha mindkettő string, de ezt az esetet már nem akarom vizsgálni. Valszeg ugyanannyi erőforrásba kerülne.

" Ez JS-ben nem működik jól, ezért stringgé kell konvertálnom a number-t. De csak akkor, ha különbözik a típusuk."
Viszont nem azt nézed, hogy különbözőek a típusok, hanem azt, hogy legalább az egyik string.
Attól még lehetnek egyező típusúak is (mindkettő string).
Nézd azt, hogy typeof z1 !== typeof z2, és máris azt csinálod, amit tényleg csinálni akarsz.

Ez jó, valóban, eszembe juthatott volna a === mintájára, meg a Math.min-t is beleteszem, kösz az opt-ot. (CS alatt != van csak, ő pedig mindenképp !== -re fordít, ugyanígy, == -> ===)

Közben tovább optimalizálom. A "break if" résznél nem kell a string-gé konvertálás előtti eredeti értékeket felhasználnom az összehasonlításra (mondván hogy addig megyek míg különböző értékeket nem találok a pároknál, mert ott biztos hogy eldől hogy kisebb vagy nagyobb), mert a regex-es split úgyis külön teszi az elemet ha számot talál (és így az csak szám lesz), ezért úgysem lesz egyforma string-ként sem ha nem egyezik eredetileg a típus, ezért nyugodtan hasonlíthatom a konvertálás utáni értékeket.

Így egy tömbös table lookup-ot talán spórolok. Bár a JIT és VM opt-ok miatt gondolom nem.

Illetve ugye a tömb <> tömb összehasonlításnál az első különböző elemükig vizsgálom az összehasonlítást, mert ott eldől hogy kisebb vagy nagyobb. Amíg egyforma, addig mennem kell tovább.

Ez teljesen egyértelmű, látszik, hogy mit csinál a kódod, csak vannak benne olyan részek, amelyek nem azt fejezik ki a kódban, mit amit tényleg csinálni akarnál.

Szam-szam osszehasonlitasra van a localeCompare numeric:true-val. Az a hello3-at a hello13 ele teszi:

"hello3".localeCompare("hello13", undefined, {numeric: true}) => -1

Rálesek.

Köszi. Ennyi gondom van localCompare-rel kapcsolatban az "options" résznél a "numeric" értéknél:

Idézet:
Implementations are not required to support this property.

Még tesztelem.

Szerk.: Az IE11 is elég fájdalmas, de hát IE-nél már megszoktuk. Mindenesetre jó tudni erről a compare-ről, jó hogy támogat locale-t meg több más opciót.