Object sorting? Topic is solved

Get help with using AutoHotkey (v1.1 and older) and its commands and hotkeys
chinagreenelvis
Posts: 133
Joined: 19 Oct 2015, 16:21

Object sorting?

Post by chinagreenelvis » 24 Jan 2022, 00:28

Right now, I have this code which takes a file that has two columns of information in this format:

Code: Select all

filename    "game title"
filename2   "game title 2"
and adds the information to an object:

Code: Select all

ListFullData := []
FileRead, ListFullText, ListFull.txt
Loop, Parse, ListFullText, `n, `r
{
	;MsgBox, %A_LoopField%
	RegExMatch(A_LoopField, "([^""]*)""(.*)""", Match)
	ListFullData.Push({FileName: Trim(Match1), GameTitle: Match2})
}
The only problem is that I need to parse that object in alphabetical order according to the game title, whereas the original file has them in alphabetical order by filename. Is there a way I can sort the ListFullData object by the GameTitle property?

User avatar
Chunjee
Posts: 1417
Joined: 18 Apr 2014, 19:05
Contact:

Re: Object sorting?

Post by Chunjee » 24 Jan 2022, 01:09

https://biga-ahk.github.io/biga.ahk/#/?id=sortby can help you.

Code: Select all

A := new biga() ; requires https://www.npmjs.com/package/biga.ahk

ListFullData := [{FileName: "...", GameTitle: "Legend Of Zelda"}
			, {FileName: "...", GameTitle: "Super Smash Bros"}
			, {FileName: "...", GameTitle: "Bomber Man 64"}]

sortedData := A.sortBy(ListFullData, "GameTitle")
/* => [{"FileName": "...", "GameTitle": "Bomber Man 64"}
	, {"FileName": "...", "GameTitle": "Legend Of Zelda"}
	, {"FileName": "...", "GameTitle": "Super Smash Bros"}]
*/
Creates an array of elements, sorted in ascending order by the results of running each element in a collection thru each iteratee. This method performs a stable sort, that is, it preserves the original sort order of equal elements. The iteratees are invoked with one argument: (value)

please note; the input array is not modified. A new sorted array is returned.

teadrinker
Posts: 4325
Joined: 29 Mar 2015, 09:41
Contact:

Re: Object sorting?

Post by teadrinker » 24 Jan 2022, 03:30

You don't need sorting an object, just sort ListFullText, then create the object.

User avatar
boiler
Posts: 16900
Joined: 21 Dec 2014, 02:44

Re: Object sorting?

Post by boiler » 24 Jan 2022, 05:22

Or don't sort anything. Just change one line to make the title the array's key. Then when you enumerate the array, it will do so in alphabetical order by title. You would only need to replace this line:

Code: Select all

	ListFullData.Push({FileName: Trim(Match1), GameTitle: Match2})
...with this:

Code: Select all

	ListFullData[Match2] := {FileName: Trim(Match1), GameTitle: Match2}

Demo:

Code: Select all

ListFullText =
(
filename    "World of Warcraft"
filename2   "Minecraft"
filename3	"Red Dead Redemption"
filename4	"League of Legends"
filename5	"Halo Infinite"
)

ListFullData := []
Loop, Parse, ListFullText, `n, `r
{
	RegExMatch(A_LoopField, "([^""]*)""(.*)""", Match)
	ListFullData[Match2] := {FileName: Trim(Match1), GameTitle: Match2}
}

; act on each item in alphabetical order of title:
for Each, Item in ListFullData
	MsgBox, % "File name: " Item.FileName "`n`nTitle: " Item.GameTitle

User avatar
boiler
Posts: 16900
Joined: 21 Dec 2014, 02:44

Re: Object sorting?  Topic is solved

Post by boiler » 24 Jan 2022, 05:27

A better alternative to the above is to make the game title only the key and not one of the values, then you don't even need an array with two properties inside each array element. Now you just have an associative array with the game title as the key and the file name as the value. So just change the line that assigns the elements to the array to this:

Code: Select all

	ListFullData[Match2] := Trim(Match1)

Enumerating the array is even easier and in alphabetical order by game title:

Code: Select all

ListFullText =
(
filename    "World of Warcraft"
filename2   "Minecraft"
filename3	"Red Dead Redemption"
filename4	"League of Legends"
filename5	"Halo Infinite"
)

ListFullData := {}
Loop, Parse, ListFullText, `n, `r
{
	RegExMatch(A_LoopField, "([^""]*)""(.*)""", Match)
	ListFullData[Match2] := Trim(Match1)
}

; act on each item in alphabetical order of game title:
for GameTitle, FileName in ListFullData
	MsgBox, % "File name: " FileName "`n`nGameTitle: " GameTitle

It has the extra (main?) advantage of not having to search for a game title to get its filename since the game title is the key. You would just do this:

Code: Select all

MsgBox, % ListFullData["League of Legends"] ; result: filename4

chinagreenelvis
Posts: 133
Joined: 19 Oct 2015, 16:21

Re: Object sorting?

Post by chinagreenelvis » 24 Jan 2022, 19:35

I think this might be the solution I'm looking for, just in a different context.

One quirk: the first game that gets listed is "005", but the key gets written as "5".
Last edited by chinagreenelvis on 24 Jan 2022, 19:42, edited 2 times in total.

User avatar
boiler
Posts: 16900
Joined: 21 Dec 2014, 02:44

Re: Object sorting?

Post by boiler » 24 Jan 2022, 19:38

Yeah, I see why it would do that. Force it to see the title as a string, not a number, by concatenating it with a null string by changing the assignment line to this:

Code: Select all

	ListFullData["" Match2] := Trim(Match1)

chinagreenelvis
Posts: 133
Joined: 19 Oct 2015, 16:21

Re: Object sorting?

Post by chinagreenelvis » 24 Jan 2022, 19:55

That works, thanks! Unfortunate that it isn't able to sort the titles in a more logical order where 99 comes before 2000, but that's a minor inconvenience that can be fixed in the original ListFull.txt anywhere it's a problem.

User avatar
boiler
Posts: 16900
Joined: 21 Dec 2014, 02:44

Re: Object sorting?

Post by boiler » 24 Jan 2022, 22:37

Well, if you want to have them sorted that way, you could follow teadrinker’s suggestion and presort the list. Then you can have your sorting routine handle numbers numerically instead of alphanumerically. Some people have already written such routines that you can find on the forum.

Post Reply

Return to “Ask for Help (v1)”