| Bytes | Lang | Time | Link |
|---|---|---|---|
| 162 | Python 3 | 250429T230801Z | CrSb0001 |
| 080 | Charcoal | 191014T210731Z | Neil |
| 038 | 05AB1E | 191007T154951Z | Grimmy |
| 137 | JavaScript ES6 | 191006T215136Z | Arnauld |
Python 3, 164 162 bytes
Same method as @Arnauld.
lambda a:''.join([*map(lambda x:x[4:],sorted(["ANBCODEFPGQSHRIJKLM"[(n:=ord(c)-44032)//588]+"AKBLCMDNERTOFGSUPHIQJ"[n//28%21]+str(~(n%28%18==2))+c for c in a]))])
There was actually a bug in the 164 byte program so that it didn't work for the all-trailing-consonant test case given in the comment section, but I managed to fix that along with finding another 1-byte save. In total, I managed to save 2 bytes.
If output is allowed to be a list of characters, then I can remove the ''.join(...) to get 153 bytes:
lambda a:[*map(lambda x:x[4:],sorted(["ANBCODEFPGQSHRIJKLM"[(n:=ord(c)-44032)//588]+"AKBLCMDNERTOFGSUPHIQJ"[n//28%21]+str(~(n%28%18==2))+c for c in a]))]
Charcoal, 80 bytes
F”&→∧⁶⍘⎚%γD¦ρJG”F”E⎇↓Nη⊙��⭆Ws@}4”F”E↖hY9 t⟧⊙γIO↶5ε∧¬⁶⦃”Φθ⁼℅μΣ⟦⁴⁴⁰³²×⌕βι⁵⁸⁸⍘⁺κλ²⁸
Try it online! Link is to verbose version of code. Explanation: Works by generating all 11172 Hangul syllables in North Korean dictionary order and checking to see which ones are present in the input (so all other characters get deleted; also somewhat slow: takes 18 seconds on TIO). Explanation:
F”&→∧⁶⍘⎚%γD¦ρJG”
Loop over the compressed string acdfghjmopqrsbeiknl. This represents the list of South Korean initial consonants (numbered using the Western lowercase alphabet) in North Korean dictionary order.
F”E⎇↓Nη⊙��⭆Ws@}4”
Loop over the compressed string 02468cdhik1357bgj9eaf. This represents the list of South Korean vowels (numbered using ASCII digits and lowercase alphabet) in North Korean dictionary order.
F”E↖hY9 t⟧⊙γIO↶5ε∧¬⁶⦃”
Loop over the compressed string 013456789abcdefghijlmnopqr2k. This represents the list of South Korean final consonants (using the same numbering as the vowels) in North Korean dictionary order.
Φθ⁼℅μΣ⟦⁴⁴⁰³²×⌕βι⁵⁸⁸⍘⁺κλ²⁸
Concatenate the vowel and final consonant and decode as a base 28 number, then add on 588 times the initial vowel and 0xAC00. Print all characters from the input that have that as their ordinal.
05AB1E, 47 45 38 bytes
Σ•¡®šúIтÝ„Š’#„λ†x!·“•4B33¡€.ā`ââyÇ68+è
Σ # sort characters of the input by:
•...• # compressed integer 13096252834522000035292405913882127943177557
4B # converted to base 4: 211211121231211111033010101010231002310010331121111111111111111121111111
33¡ # split on 33: [2112111212312111110, 010101010231002310010, 1121111111111111111121111111]
€.ā # enumerate each (pairs each digit with its index)
`ââ # reduce by cartesian product (yields a list with 11172 elements)
yÇ # codepoint of the current character
68+ # + 68
è # index into the large list (with wraparound)
JavaScript (ES6), 150 148 137 bytes
Saved 10 bytes thanks to @Grimy
I/O: arrays of characters.
a=>a.map(c=>"ANBCODEFPGQSHRIJKLM"[(n=c.charCodeAt()-44032)/588|0]+"AKBLCMDNERTOFGSUPHIQJ"[n/28%21|0]+~(n%28%18==2)+c).sort().map(s=>s[4])
Splitting Hangul syllables
Given a Hangul character of code point 0xAC00 + \$n\$, the initial consonant \$I\$, vowel \$V\$ and final consonant \$F\$ are given by:
$$I=\left\lfloor\frac{n}{588}\right\rfloor,\ V=\left\lfloor\frac{n}{28}\right\rfloor\bmod 21,\ F=n\bmod 28$$
Commented
a => a.map(c => // for each character c in the input:
"ANBCODEFPGQSHRIJKLM"[ // start with a letter from 'A' to 'S'
(n = c.charCodeAt() - 44032) // for the initial consonant
/ 588 | 0 //
] + //
"AKBLCMDNERTOFGSUPHIQJ"[ // append a letter from 'A' to 'U'
n / 28 % 21 | 0 // for the vowel
] + //
~( // append "-2" for ㄲ or ㅆ (the only North
n % 28 % 18 == 2 // Korean final consonants that are sorted
) + // differently) or "-1" otherwise
c // append the original character
) // end of map()
.sort() // sort in lexicographical order
.map(s => s[4]) // isolate the original characters