Natural sort Topic is solved

Get help with using AutoHotkey (v1.1 and older) and its commands and hotkeys
ahknewguy
Posts: 20
Joined: 02 Apr 2020, 12:13

Natural sort

02 Apr 2020, 12:23

Hi everyone,

with javascript it's possible to sort this list:

2
File 20.png
File 3.tmp
1
10
Test - 9 - fjg
1234567
File 9.abc
Test - 2 - zgrg
Test - 1 - gshsgh
Test - 10 - tjfmn
Test - 11 - mnulk
File 1.ahk
File 2
Test - 15 - bnn
1234568
Test - 15 - jfgjgfm

into this:

1
2
10
1234567
1234568
File 1.ahk
File 2
File 3.tmp
File 9.abc
File 20.png
Test - 1 - gshsgh
Test - 2 - zgrg
Test - 9 - fjg
Test - 10 - tjfmn
Test - 11 - mnulk
Test - 15 - bnn
Test - 15 - jfgjgfm

How can I do the same with AHK? Thanks.
HotKeyIt
Posts: 2364
Joined: 29 Sep 2013, 18:35
Contact:

Re: Natural sort

02 Apr 2020, 15:22

Try:

Code: Select all

text:="
(
2
File 20.png
File 3.tmp
1
10
Test - 9 - fjg
1234567
File 9.abc
Test - 2 - zgrg
Test - 1 - gshsgh
Test - 10 - tjfmn
Test - 11 - mnulk
File 1.ahk
File 2
Test - 15 - bnn
1234568
Test - 15 - jfgjgfm
)"
MsgBox % nsort(text)
nSort(s){
    Sort, s
    If p:=RegExMatch(s,"`a)\R[^\d\R]"){
        a:=SubStr(s,1,p-1),b:=SubStr(s,p)
        Sort, a, N
        s:= a b
    }
    return s
}
ahknewguy
Posts: 20
Joined: 02 Apr 2020, 12:13

Re: Natural sort

02 Apr 2020, 16:09

HotKeyIt wrote:
02 Apr 2020, 15:22
Try:
Hi, HotKeyIt, thanks for the help.

So I tried but I get this:

1
2
10
1234567
1234568
File 1.ahk
File 2
File 20.png
File 3.tmp
File 9.abc
Test - 1 - gshsgh
Test - 10 - tjfmn
Test - 11 - mnulk
Test - 15 - bnn
Test - 15 - jfgjgfm
Test - 2 - zgrg
Test - 9 - fjg

The numbers are ok but the strings with numbers in the middle still get mixed up.

This is quite annoying. I couldn't find an answer even in the old forums. Why is this stuff not a feature?
User avatar
boiler
Posts: 17390
Joined: 21 Dec 2014, 02:44

Re: Natural sort

02 Apr 2020, 16:24

That's not sorting numerically within the same group of items that start with the same non-numeric characters as was shown in the desired output:
sort comparison.png
sort comparison.png (13.05 KiB) Viewed 2127 times

Seems like a pretty complicated sort. I started something and then saw how involved it was going to be.
HotKeyIt
Posts: 2364
Joined: 29 Sep 2013, 18:35
Contact:

Re: Natural sort

02 Apr 2020, 16:50

Found on the old forums: https://autohotkey.com/board/topic/32820-natural-sorting/
Following can handle up to 100 numbers in string:

Code: Select all

s:="
(
2
File 20.png
File 3.tmp
1
10
Test - 9 - fjg
1234567
File 9.abc
Test - 2 - zgrg
Test - 1 - gshsgh
Test - 10 - tjfmn
Test - 11 - mnulk
File 1.ahk
File 2
Test - 15 - bnn
1234568
Test - 15 - jfgjgfm
)"
Sort, s,F cmp
MsgBox % s
cmp(x,y) {
   RegExMatch(x,"(\D*)(\d*)(\D*)(\d*)(\D*)(\d*)(\D*)(\d*)(\D*)(\d*)(\D*)(\d*)(\D*)(\d*)(\D*)(\d*)(\D*)(\d*)(\D*)(\d*)(\D*)(\d*)(\D*)(\d*)(\D*)(\d*)(\D*)(\d*)(\D*)(\d*)(\D*)(\d*)(\D*)(\d*)(\D*)(\d*)(\D*)(\d*)(\D*)(\d*)(\D*)(\d*)(\D*)(\d*)(\D*)(\d*)(\D*)(\d*)(\D*)(\d*)(\D*)(\d*)(\D*)(\d*)(\D*)(\d*)(\D*)(\d*)(\D*)(\d*)(\D*)(\d*)(\D*)(\d*)(\D*)(\d*)(\D*)(\d*)(\D*)(\d*)(\D*)(\d*)(\D*)(\d*)(\D*)(\d*)(\D*)(\d*)(\D*)(\d*)(\D*)(\d*)(\D*)(\d*)(\D*)(\d*)(\D*)(\d*)(\D*)(\d*)(\D*)(\d*)(\D*)(\d*)(\D*)(\d*)(\D*)(\d*)(\D*)(\d*)(\D*)(\d*)(\D*)(\d*)(\D*)(\d*)(\D*)(\d*)(\D*)(\d*)(\D*)(\d*)(\D*)(\d*)(\D*)(\d*)(\D*)(\d*)(\D*)(\d*)(\D*)(\d*)(\D*)(\d*)(\D*)(\d*)(\D*)(\d*)(\D*)(\d*)(\D*)(\d*)(\D*)(\d*)(\D*)(\d*)(\D*)(\d*)(\D*)(\d*)(\D*)(\d*)(\D*)(\d*)(\D*)(\d*)(\D*)(\d*)(\D*)(\d*)(\D*)(\d*)(\D*)(\d*)(\D*)(\d*)(\D*)(\d*)(\D*)(\d*)(\D*)(\d*)(\D*)(\d*)(\D*)(\d*)(\D*)(\d*)(\D*)(\d*)(\D*)(\d*)(\D*)(\d*)(\D*)(\d*)(\D*)(\d*)(\D*)(\d*)(\D*)(\d*)(\D*)(\d*)(\D*)(\d*)(\D*)(\d*)(\D*)(\d*)(\D*)(\d*)(\D*)(\d*)(\D*)(\d*)(\D*)(\d*)(\D*)(\d*)(.*)",x)
   ,RegExMatch(y,"(\D*)(\d*)(\D*)(\d*)(\D*)(\d*)(\D*)(\d*)(\D*)(\d*)(\D*)(\d*)(\D*)(\d*)(\D*)(\d*)(\D*)(\d*)(\D*)(\d*)(\D*)(\d*)(\D*)(\d*)(\D*)(\d*)(\D*)(\d*)(\D*)(\d*)(\D*)(\d*)(\D*)(\d*)(\D*)(\d*)(\D*)(\d*)(\D*)(\d*)(\D*)(\d*)(\D*)(\d*)(\D*)(\d*)(\D*)(\d*)(\D*)(\d*)(\D*)(\d*)(\D*)(\d*)(\D*)(\d*)(\D*)(\d*)(\D*)(\d*)(\D*)(\d*)(\D*)(\d*)(\D*)(\d*)(\D*)(\d*)(\D*)(\d*)(\D*)(\d*)(\D*)(\d*)(\D*)(\d*)(\D*)(\d*)(\D*)(\d*)(\D*)(\d*)(\D*)(\d*)(\D*)(\d*)(\D*)(\d*)(\D*)(\d*)(\D*)(\d*)(\D*)(\d*)(\D*)(\d*)(\D*)(\d*)(\D*)(\d*)(\D*)(\d*)(\D*)(\d*)(\D*)(\d*)(\D*)(\d*)(\D*)(\d*)(\D*)(\d*)(\D*)(\d*)(\D*)(\d*)(\D*)(\d*)(\D*)(\d*)(\D*)(\d*)(\D*)(\d*)(\D*)(\d*)(\D*)(\d*)(\D*)(\d*)(\D*)(\d*)(\D*)(\d*)(\D*)(\d*)(\D*)(\d*)(\D*)(\d*)(\D*)(\d*)(\D*)(\d*)(\D*)(\d*)(\D*)(\d*)(\D*)(\d*)(\D*)(\d*)(\D*)(\d*)(\D*)(\d*)(\D*)(\d*)(\D*)(\d*)(\D*)(\d*)(\D*)(\d*)(\D*)(\d*)(\D*)(\d*)(\D*)(\d*)(\D*)(\d*)(\D*)(\d*)(\D*)(\d*)(\D*)(\d*)(\D*)(\d*)(\D*)(\d*)(\D*)(\d*)(\D*)(\d*)(\D*)(\d*)(\D*)(\d*)(\D*)(\d*)(\D*)(\d*)(\D*)(\d*)(\D*)(\d*)(\D*)(\d*)(.*)",y)
   Loop 201
      If (x%A_Index% != y%A_Index%)
         Return 2*(x%A_Index%>y%A_Index%) - 1
}
ahknewguy
Posts: 20
Joined: 02 Apr 2020, 12:13

Re: Natural sort

02 Apr 2020, 17:13

boiler wrote:
02 Apr 2020, 16:24
Seems like a pretty complicated sort. I started something and then saw how involved it was going to be.
I guess it is, but I think it's a pretty important one. I hoped someone had already worked it out years ago. Closest thing I found is here (credits to Laszlo):

Code: Select all

dfhfdahad := Clipboard
MsgBox % Sort(dfhfdahad)

Sort(x, delim="`n") {
	x := x . "`n"
   IfEqual delim,, SetEnv delim, `n
   Sort x, D%delim%
   Loop Parse, x, %delim%
   {
      If (p = PreText(A_LoopField))
         y = %y%%delim%%A_LoopField%
      Else {
         Sort y, % "N D" delim " P" StrLen(p)+1
         z = %z%%y%%delim%
         p := PreText(A_LoopField)
         y = %A_LoopField%
      }
   }
   StringTrimLeft z, z, 1
   Return z
}

PreText(x) {
   Loop Parse, x, 0123456789
      Return A_LoopField
}
It doesn't work too well:

1
2
10
1234567
1234568
File 1.ahk
File 2
File 3.tmp
File 9.abc
File 20.png
Test - 1 - gshsgh
Test - 2 - zgrg
Test - 9 - fjg
Test - 10 - tjfmn
Test - 11 - mnulk
Test - 15 - jfgjgfm <----
Test - 15 - bnn <----
ahknewguy
Posts: 20
Joined: 02 Apr 2020, 12:13

Re: Natural sort

02 Apr 2020, 17:55

HotKeyIt wrote:
02 Apr 2020, 16:50
Found on the old forums: https://autohotkey.com/board/topic/32820-natural-sorting/
Following can handle up to 100 numbers in string:
...
Thanks, HotKeyIt, for pointing out that thread. How about this one by animeaime in the next page:
I was showed this thread and it is exactly what I was looking for. I tweaked Laszlo's solution from a few posts ago because I need to allow sorting regardless how many numbers are in the string - looking for performance feedback.

Code: Select all

LogicalSort(x,y,offset)
{
    static RegEx := "S)(\D*)(\d*)(.*)"
    
    Loop
    {
        RegExMatch(x, RegEx, x)
        RegExMatch(y, RegEx, y)
        
        if (x1 != y1)
            return x1 < y1 ? -1 : 1
            
        if (x2 != y2)
            return x2 < y2 ? -1 : 1
            
        if (x3 = "" || y3 = "")
            break
            
        x := x3
        y := y3
    }

    if (x3 != "")
    {
        ;x is "longer"
        return 1
    }
    else if (y3 != "")
    {
        ;y is "longer"
        return -1
    }
    else
    {
        ;equal - maintain original order (stable)
        return -offset
    }
}
It seems this one has no number limitations and it seems to work but I've no idea if it's reliable.
User avatar
boiler
Posts: 17390
Joined: 21 Dec 2014, 02:44

Re: Natural sort

02 Apr 2020, 18:17

ahknewguy wrote:
02 Apr 2020, 17:13
I hoped someone had already worked it out years ago. Closest thing I found is here (credits to Laszlo):
...
It doesn't work too well
I guess you didn’t notice that HotKeyIt posted a script that produces the correct output in the post before yours.
ahknewguy
Posts: 20
Joined: 02 Apr 2020, 12:13

Re: Natural sort

02 Apr 2020, 18:28

I have missed some posts, sorry!

I think I found the best solution here, courtesy of jeeswg: :dance:
jeeswg wrote:
23 Apr 2019, 08:32
- You can make use of the StrCmpLogicalW function, to sort items like Explorer sorts file names.
- Note: there is no StrCmpLogicalA or ANSI equivalent function, however, by using 'WStr', you can use the function with ANSI versions of AutoHotkey.
- WStr converts ANSI strings into Unicode strings in ANSI versions of AHK. WStr leaves Unicode strings unchanged in Unicode versions of AHK.

Code: Select all

q:: ;sort using StrCmpLogicalW
List := "
(
Chapter 3
Chapter 1
Chapter 999
Chapter 10
Chapter -69
Chapter 2
)"

Sort, List, F SortStrCmpLogical
MsgBox, % List
return

SortStrCmpLogical(vTextA, vTextB, vOffset) ;for use with AHK's Sort command
{
	local
	vRet := DllCall("shlwapi\StrCmpLogicalW", "WStr",vTextA, "WStr",vTextB)
	return vRet ? vRet : -vOffset
}

If not a feature of AHK, this should at least be in the documentation as an example or something.

Thanks, to boiler and HotKeyIt! :bravo:
Helgef
Posts: 4709
Joined: 17 Jul 2016, 01:02
Contact:

Re: Natural sort  Topic is solved

02 Apr 2020, 23:24

You use this function, :arrow: StrCmpLogical and use :arrow: sort with F MyFunction option, example,

Code: Select all

logical_sort(byref str) {
	sort str, % "f logical_cmp"
}
logical_cmp(a,b, o) {
	return dllcall("Shlwapi.dll\StrCmpLogicalW", "wstr", a, "wstr", b, "int")
}
Cheers.
v2
ahknewguy
Posts: 20
Joined: 02 Apr 2020, 12:13

Re: Natural sort

03 Apr 2020, 04:25

Hi, Helgef! Thank you for your answer.

I have a couple of things I'd like to ask you. What's the difference, if any, between StrCmpLogicalW', 'ptr' and StrCmpLogicalW", "wstr" ? Also is it possible to use this function to sort the elements of an array?

Thanks.
Helgef
Posts: 4709
Joined: 17 Jul 2016, 01:02
Contact:

Re: Natural sort

03 Apr 2020, 06:59

You have to use wstr for ANSI compatibility, when you use wstr(or astr orstr) AHK will also update the string's length after the call, which is a little wasteful since we know it doesn't change. By just passing 'ptr', &a you avoid that. For v2 there is no ansi version so ptr is OK. You can use ptr for v1 unicode build too, if you like.

:arrow: Sort doesn't support sorting arrays, there are custom sorting functions for arrays, you can probably find one which supports custom sort functions, then use the logical_cmp. function.

Cheers.

Edit, my posts in this thread looks a bit weird, but when I posted them, :arrow: this post hadn't been approved by a moderator, so I couldn't see it.
Odlanir
Posts: 659
Joined: 20 Oct 2016, 08:20

Re: Natural sort

03 Apr 2020, 11:26

You can do this way:

Code: Select all

Array := ["2","File 20.png","File 3.tmp","1","10","Test - 9 - fjg","1234567","File 9.abc","Test - 2 - zgrg","Test - 1 - gshsgh","Test - 20 - tjfmn","Test - 11 - mnulk","File 1.ahk","File 2","Test - 15 - bnn","1234568","Test - 15 - jfgjgfm"]

for k,v in Array 
   str .= str ? "`n" v : v 
sort str, % "f logical_cmp"
Array := StrSplit(str, "`n" )
ExitApp

logical_cmp(a,b, o) {
	return dllcall("Shlwapi.dll\StrCmpLogicalW", "wstr", a, "wstr", b, "int")
}
____________________________________________________________________________
Windows 10 Pro 64 bit - Autohotkey v1.1.30.01 64-bit Unicode
User avatar
Chunjee
Posts: 1499
Joined: 18 Apr 2014, 19:05
Contact:

Re: Artificial sort

03 Apr 2020, 16:15

ahknewguy wrote:
02 Apr 2020, 12:23
Hi everyone,

with javascript it's possible to sort this list
Javascript default array sort sorts your list into the following:

Code: Select all

var array = ["2","File 20.png","File 3.tmp","1","10","Test - 9 - fjg","1234567","File 9.abc","Test - 2 - zgrg","Test - 1 - gshsgh","Test - 20 - tjfmn","Test - 11 - mnulk","File 1.ahk","File 2","Test - 15 - bnn","1234568","Test - 15 - jfgjgfm"]

console.log(array.sort())
/*
[ '1',
  '10',
  '1234567',
  '1234568',
  '2',
  'File 1.ahk',
  'File 2',
  'File 20.png',
  'File 3.tmp',
  'File 9.abc',
  'Test - 1 - gshsgh',
  'Test - 11 - mnulk',
  'Test - 15 - bnn',
  'Test - 15 - jfgjgfm',
  'Test - 2 - zgrg',
  'Test - 20 - tjfmn',
  'Test - 9 - fjg' ]
*/
Please rename thread "Artificial sort"



https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort
The time and space complexity of the sort cannot be guaranteed as it depends on the implementation.
ahknewguy
Posts: 20
Joined: 02 Apr 2020, 12:13

Re: Artificial sort

04 Apr 2020, 09:09

Chunjee wrote:
03 Apr 2020, 16:15
Javascript default array sort sorts your list into the following:
...
I never talked about default. Javascript can do natural sort perfectly well if you use Intl.Collator. I have code that does that.

https://stackoverflow.com/questions/2802341/javascript-natural-sort-of-alphanumerical-strings/38641281
https developer.mozilla.org /en-US/docs/Web/JavaScript/Reference/Global_Objects/Collator

Chunjee wrote:
03 Apr 2020, 16:15
Please rename thread "Artificial sort"
Nope. Natural sort is what it's called.

https en.wikipedia.org /wiki/Natural_sort_order

Return to “Ask for Help (v1)”

Who is online

Users browsing this forum: Rohwedder, Rxbie and 158 guests