2

This is how qBittorrent, a BitTorrent client, sorts names of files.

qBittorrent’s file sorting Disclaimer: I’m not interested in the torrent and the files, don’t know what those are, and haven’t downloaded any one of those.

How do you sort strings in Javascript in this manner? I don’t quite get the logic, but it is certainly not random.

I tried this

strings.sort((a, b) => a.localeCompare(b, "en", {
    sensitivity: "case",
    caseFirst: "upper",
    numeric: true
}));

But this was what I got, which is not what I intended

[
    "1.ico",
    "01.ico",
    "03.ico",
    "04.ico",
    "05.ico",
    "7-zip ICO m1losh_1.ico",
    "07.ico",
    "7z-silver.ico",
    "7z.ico",
    "7z1.ico",
    "7zfm.ico",
    "7Zip.ico",
    "7ZSFX.ico",
    "7zSfxCreate_99.ico",
    "7ZSplit.ico",
    "7zz.ico",
    "08.ico",
    "09.ico",
    "11.ico",
    "14.ico",
    "22.ico",
    "101.ico",
    "107.ico",
    "128.ico",
    "138.ico",
    "777.ico",
    "7833-ZeDudeMan-WinRar_vista.ico",
    "exe.ico",
    "hfs.ico",
    "hg.ico",
    "Icon.ico",
    "Icon1.ico",
    "icon17.ico",
    "inst.ico",
    "Install-2.ico",
    "Install-3.ico",
    "Install-4.ico",
    "Install-5.ico",
    "Install-6.ico",
    "Install-7.ico",
    "Install-8.ico",
    "Install-9.ico",
    "Install-11.ico",
    "Install-12.ico",
    "Install-13.ico",
    "Install-14.ico",
    "Install-15.ico",
    "Install-16.ico",
    "Install-17.ico",
    "Install-18.ico",
    "MAINICON.ico",
    "momitor.ico",
    "PSA_1.ico",
    "qfInstall.ico",
    "Readme!!!.txt",
    "Token_7zip-dark.ico",
    "Token_7zip-light.ico",
    "wusa.ico"
]
  • What is the logic for sorting? – adiga Apr 22 '21 at 05:56
  • Exactly, what's the sorting criteria – doc-han Apr 22 '21 at 05:57
  • @adiga I don’t quite get the logic, which is what this question is for. As you can see, it is certainly not complete random. – Константин Ван Apr 22 '21 at 05:57
  • It's probably based on the number of leading numeric characters -> Then based on the actual number -> alphabetic – adiga Apr 22 '21 at 05:59
  • @adiga How do you achieve it in Javascript? – Константин Ван Apr 22 '21 at 06:01
  • 2
    I believe "natural sorting" is what you're after. http://www.davekoelle.com/alphanum.html Dave Keolle's blog has discussion around this. This may be a different but similar question: https://stackoverflow.com/questions/2802341/javascript-natural-sort-of-alphanumerical-strings – richter Apr 22 '21 at 06:04
  • @WoIIe the items starting with numbers are not sorted numerically. `01`, comes after `7`. They are grouped based on the number of numeric characters first. – adiga Apr 22 '21 at 06:04
  • 1
    I believe they're sorted by the order of the files in the torrent. – Brad Apr 22 '21 at 06:10
  • @Brad You’re saying that the logic could be not based on the filenames; in other words, they could have been sorted by creation dates or so when they were packed into a torrent. I see. But nevertheless, it seems to me regular enough to be able to come up with sorting criteria that work like this. – Константин Ван Apr 22 '21 at 06:22
  • 1
    @КонстантинВан Yeah, not saying you can't recreate the order, only that it may vary from torrent to torrent. – Brad Apr 22 '21 at 06:23

2 Answers2

3

Sort based on:

  • Whether the item starts with a number
  • Then, based on the number of characters in the leading number
  • Then, do a natural sort

const array=["1.ico","01.ico","03.ico","04.ico","05.ico","7-zip ICO m1losh_1.ico","07.ico","7z-silver.ico","7z.ico","7z1.ico","7zfm.ico","7Zip.ico","7ZSFX.ico","7zSfxCreate_99.ico","7ZSplit.ico","7zz.ico","08.ico","09.ico","11.ico","14.ico","22.ico","101.ico","107.ico","128.ico","138.ico","777.ico","7833-ZeDudeMan-WinRar_vista.ico","exe.ico","hfs.ico","hg.ico","Icon.ico","Icon1.ico","icon17.ico","inst.ico","Install-2.ico","Install-3.ico","Install-4.ico","Install-5.ico","Install-6.ico","Install-7.ico","Install-8.ico","Install-9.ico","Install-11.ico","Install-12.ico","Install-13.ico","Install-14.ico","Install-15.ico","Install-16.ico","Install-17.ico","Install-18.ico","MAINICON.ico","momitor.ico","PSA_1.ico","qfInstall.ico","Readme!!!.txt","Token_7zip-dark.ico","Token_7zip-light.ico","wusa.ico"];

array.sort((a, b) => {
    const n1 = a.match(/^\d+/)?.[0],
          n2 = b.match(/^\d+/)?.[0]

    return (n1 === null) - (n2 === null)
           || n1?.length - n2?.length
           || a.localeCompare(b, undefined, {numeric: true, sensitivity: 'base'})
})

console.log(array)
adiga
  • 34,372
  • 9
  • 61
  • 83
  • 2
    Yeah, this seems to be the solution. My take: https://jsfiddle.net/ucop0L7a/ –  Apr 22 '21 at 06:24
0

Modified @adiga and @Chris G’s code[a.][C.] a bit.

const strings = ["1.ico","01.ico","03.ico","04.ico","05.ico","7-zip ICO m1losh_1.ico","07.ico","7z-silver.ico","7z.ico","7z1.ico","7zfm.ico","7Zip.ico","7ZSFX.ico","7zSfxCreate_99.ico","7ZSplit.ico","7zz.ico","08.ico","09.ico","11.ico","14.ico","22.ico","101.ico","107.ico","128.ico","138.ico","777.ico","7833-ZeDudeMan-WinRar_vista.ico","exe.ico","hfs.ico","hg.ico","Icon.ico","Icon1.ico","icon17.ico","inst.ico","Install-2.ico","Install-3.ico","Install-4.ico","Install-5.ico","Install-6.ico","Install-7.ico","Install-8.ico","Install-9.ico","Install-11.ico","Install-12.ico","Install-13.ico","Install-14.ico","Install-15.ico","Install-16.ico","Install-17.ico","Install-18.ico","MAINICON.ico","momitor.ico","PSA_1.ico","qfInstall.ico","Readme!!!.txt","Token_7zip-dark.ico","Token_7zip-light.ico","wusa.ico"];

strings.sort((a, b) =>
    ((a.match(/^\d+/)?.[0].length || Infinity) - (b.match(/^\d+/)?.[0].length || Infinity))
        || a.localeCompare(b, "en-u-kf-upper-kn", {sensitivity: "base"})
);

console.log(strings);