It is currently May 27th, 2024, 8:12 pm

Sort information in lua

Discuss the use of Lua in Script measures.
User avatar
balala
Rainmeter Sage
Posts: 16267
Joined: October 11th, 2010, 6:27 pm
Location: Gheorgheni, Romania

Sort information in lua

Post by balala »

Hello everyone,

I have a Lua-related question, maybe someone out there will be able to help me with.
I have a skin which reads some information from a .inc file, then sort them in alphabetical order, using a Lua script. Finally it should write these sorted information into another .inc file (obviously in sorted order). The problem is that the code reads the information, the script sorts them, but when they are written into the new file, their order is random. I know the information have been sorted, because I added a simple String meter, to see the information and they are indeed sorted, however when written into the file, as said, their order has nothing to do with the order of the sorted information.
I used the ReadFileLines and the WriteIni functions from the Rainmeter Snippets, to read and write the files. I attach a simplified skin, which besides the Sort.ini skin file the contains the MyLua.lua script file and an Events.inc file, which contains the strings (in fact variables) which should be sorted (ten such variables). No need to sort them by the values set for the variables, instead they should be sorted by their name. As you can see in the skin, they are sorted in a proper order, however when written into the d:\Written.inc file (please alter the path in the 77th line of the MyLua.lua script file, if needed - yep, I know there are much more elegant ways to deal with this file, but my question is not related to this detail), their order has nothing to do with the sorted order.
Does anyone know how can I get those variables written into the sorted order?

Many thanks in advance.
You do not have the required permissions to view the files attached to this post.
User avatar
nek
Posts: 105
Joined: November 3rd, 2019, 12:00 am

Re: Sort information in lua

Post by nek »

It seems that the ploblem is for key, value in pairs(table) do ... end.

Code: Select all

function WriteIni(inputtable, filename)
	assert(type(inputtable) == 'table', ('WriteIni must receive a table. Received %s instead.'):format(type(inputtable)))

	local file = assert(io.open(filename, 'w'), 'Unable to open ' .. filename)
	local lines = {}

	for section, contents in pairs(inputtable) do
		table.insert(lines, ('\[%s\]'):format(section))
		for key, value in pairs(contents) do
			table.insert(lines, ('%s=%s'):format(key, value))
		end
		table.insert(lines, '')
	end

	file:write(table.concat(lines, '\n'))
	file:close()
end
Lua 5.1 manual wrote: The order in which the indices are enumerated is not specified, even for numeric indices. (To traverse a table in numeric order, use a numerical for or the ipairs function.) > pairs (t)
You can see the behavior of pairs at the https://www.lua.org/cgi-bin/demo using the following code. The result is randomly orderd outputted by each clicking the [run] button.

Code: Select all

local t = { a='a1', b='b2', c='c3', d='d4' }
for k,v in pairs(t) do print(k,v) end
I can use the following code

Code: Select all

local t = { {a='a1'}, {b='b2'} , {c='c3'}, {d='d4'} }

for i=1, #t do
  for k,v in pairs(t[i]) do
    print(k,v)
  end
end
or there are some solutions (I need more time to understand these pages, but you might learn something from that.)
> Ordered Table Simple | http://lua-users.org/wiki/OrderedTableSimple
> Ordered Table | http://lua-users.org/wiki/OrderedTable
User avatar
Yincognito
Rainmeter Sage
Posts: 7344
Joined: February 27th, 2015, 2:38 pm
Location: Terra Yincognita

Re: Sort information in lua

Post by Yincognito »

Nek is correct, this is a classic thing in Lua: only numerically indexed tables produce the order one expects when building the table. If you need non numeric stuff to be part of the table, place them as values, and not as indexes, i.e. some table[5]={'foo','bar'} instead of sometable['foo']='bar'. You'll have some extra table dimension added in some cases, but your table will have the order you expect, according to the numerical index.

P.S. I'm on my phone ATM so I didn't check the code, so I don't know if there are other problems than the one above. That one though is typically the culprit for what you described.
Profiles: Rainmeter ProfileDeviantArt ProfileSuites: MYiniMeterSkins: Earth
User avatar
balala
Rainmeter Sage
Posts: 16267
Joined: October 11th, 2010, 6:27 pm
Location: Gheorgheni, Romania

Re: Sort information in lua

Post by balala »

nek wrote: July 14th, 2023, 12:13 pm You can see the behavior of pairs at the https://www.lua.org/cgi-bin/demo using the following code. The result is randomly orderd outputted by each clicking the [run] button.

Code: Select all

local t = { a='a1', b='b2', c='c3', d='d4' }
for k,v in pairs(t) do print(k,v) end
I can use the following code

Code: Select all

local t = { {a='a1'}, {b='b2'} , {c='c3'}, {d='d4'} }

for i=1, #t do
  for k,v in pairs(t[i]) do
    print(k,v)
  end
end
Maybe I am missing something, but I say this is exactly what I did in the lines 60 - 65 in the MyLua.lua. Or am I wrong?
User avatar
nek
Posts: 105
Joined: November 3rd, 2019, 12:00 am

Re: Sort information in lua

Post by nek »

balala wrote: July 14th, 2023, 6:38 pm Maybe I am missing something, but I say this is exactly what I did in the lines 60 - 65 in the MyLua.lua. Or am I wrong?
lines 60 - 65 of the MyLua.lua

Code: Select all

for i = 1,#Contents do
	if (Contents[i] ~= '[Variables]') then
		Options[j], Values[j] = SplitString(Contents[i], '=')[1], SplitString(Contents[i], '=')[2]
		j = j + 1
	end
end

I meant the code is something like:

Sort.ini

Code: Select all

[Rainmeter]
Update=1000
AccurateText=1
DynamicWindowSize=1

[MeasureLuaScript]
Measure=Script
ScriptFile=#@#MyLua.lua

[MeterInfo]
Meter=STRING
MeasureName=MeasureLuaScript
X=0
Y=0
Padding=15,5,15,5
FontColor=220,220,220
FontEffectColor=0,0,0
StringEffect=Shadow
SolidColor=0,0,0,150
FontSize=8
FontFace=Segoe UI
StringStyle=BOLD
StringAlign=LEFT
AntiAlias=1
Text=[&MeasureLuaScript:ReadFileLines('#@#Events.inc')]
DynamicVariables=1
;; @modified
UpdateDivider=-1
;; @modified
MyLua.lua

Code: Select all

function SplitString(inString, inDelimiter)
--	assert(inDelimiter:len() == 1, 'SplitString: Delimiter may only be a single character')

	local outTable = {}

	for matchedString in inString:gmatch('[^%' .. inDelimiter .. ']+') do
		table.insert(outTable, matchedString)
	end

	return outTable

end

function WriteIni(inputtable, filename)
	assert(type(inputtable) == 'table', ('WriteIni must receive a table. Received %s instead.'):format(type(inputtable)))

	local file = assert(io.open(filename, 'w'), 'Unable to open ' .. filename)
	local lines = {}

	for section, contents in pairs(inputtable) do
		table.insert(lines, ('\[%s\]'):format(section))
		-- for key, value in pairs(contents) do
			-- table.insert(lines, ('%s=%s'):format(key, value))
		-- end
		-- @modified
		for i=1, #contents do
			table.insert(lines, ('%s=%s'):format(contents[i].key, contents[i].value))
		end
		-- @modified
		table.insert(lines, '')
	end

	file:write(table.concat(lines, '\n'))
	file:close()
end

function ReadFileLines(FilePath)
	-- HANDLE RELATIVE PATH OPTIONS.
	FilePath = SKIN:MakePathAbsolute(FilePath)

	-- OPEN FILE.
	local File = io.open(FilePath)

	-- HANDLE ERROR OPENING FILE.
	if not File then
		print('ReadFile: unable to open file at ' .. FilePath)
		return
	end

	-- READ FILE CONTENTS AND CLOSE.
	local Contents, Options, Values, ToWrite = {}, {}, {}, {}
	
	ToWrite['Variables'] = {}
	
	for Line in File:lines() do
		table.insert(Contents, Line)
	end

	File:close()
	
	table.sort(Contents)
	
	local j = 1
	
	for i = 1,#Contents do
		if (Contents[i] ~= '[Variables]') then
			Options[j], Values[j] = SplitString(Contents[i], '=')[1], SplitString(Contents[i], '=')[2]
			j = j + 1
		end
	end
	
	local Max = j-1
	
	-- for i = 1,Max do
		-- ToWrite['Variables'][Options[i]] = Values[i]
	-- end

	-- WriteIni(ToWrite, 'd://Written.inc')

	-- @modified
	for i = 1,Max do
		ToWrite['Variables'][i] = { key = Options[i], value = Values[i] }
	end

	WriteIni(ToWrite, SKIN:GetVariable('CURRENTPATH')..'Written.inc')
	-- @modified
	
	return '1. '..Options[1]..' = '..Values[1]
	..'\n2. '..Options[2]..' = '..Values[2]
	..'\n3. '..Options[3]..' = '..Values[3]
	..'\n4. '..Options[4]..' = '..Values[4]
	..'\n5. '..Options[5]..' = '..Values[5]
	..'\n6. '..Options[6]..' = '..Values[6]
	..'\n7. '..Options[7]..' = '..Values[7]
	..'\n8. '..Options[8]..' = '..Values[8]
	..'\n9. '..Options[9]..' = '..Values[9]
	..'\n10. '..Options[10]..' = '..Values[10]
end

function Update()
end
I feel that the function for Inline Lua should be something like just return a value.
For example, read a file and create a table in function Initialize() -> function ReadFile() and display using Inline lua.
User avatar
balala
Rainmeter Sage
Posts: 16267
Joined: October 11th, 2010, 6:27 pm
Location: Gheorgheni, Romania

Re: Sort information in lua

Post by balala »

nek wrote: July 14th, 2023, 7:55 pm I meant the code is something like:
This is great! Definitely seems to be working as expected. Have to study your solution a little bit, but at a first look, seems to do what I intended, in the way I intended.
Thank you very much for this help. Means a lot. :rosegift:
User avatar
Yincognito
Rainmeter Sage
Posts: 7344
Joined: February 27th, 2015, 2:38 pm
Location: Terra Yincognita

Re: Sort information in lua

Post by Yincognito »

balala wrote: July 14th, 2023, 8:23 pmDefinitely seems to be working as expected.
It's important to remember that this is not just a one time particularity of Lua code for this case, you'll need it in other situations too. Whenever the order in the table matters, use numerical indexing and create the table structure in a way that matches that. If order doesn't matter, the other way involving plain pairs() - as opposed to ipairs() and numerical indexing - is very much valid and sometimes even faster. ;-)
Profiles: Rainmeter ProfileDeviantArt ProfileSuites: MYiniMeterSkins: Earth
User avatar
balala
Rainmeter Sage
Posts: 16267
Joined: October 11th, 2010, 6:27 pm
Location: Gheorgheni, Romania

Re: Sort information in lua

Post by balala »

Yincognito wrote: July 14th, 2023, 8:51 pm It's important to remember that this is not just a one time particularity of Lua code for this case, you'll need it in other situations too. Whenever the order in the table matters, use numerical indexing and create the table structure in a way that matches that. If order doesn't matter, the other way involving plain pairs() - as opposed to ipairs() and numerical indexing - is very much valid and sometimes even faster. ;-)
Alright, thanks both of you for all the provided information. Makes sense.
User avatar
Yincognito
Rainmeter Sage
Posts: 7344
Joined: February 27th, 2015, 2:38 pm
Location: Terra Yincognita

Re: Sort information in lua

Post by Yincognito »

balala wrote: July 14th, 2023, 8:53 pm Alright, thanks both of you for all the provided information. Makes sense.
Nek deserves the thanks on this one entirely. I only mentioned some "principles" when working with these things, really.
Profiles: Rainmeter ProfileDeviantArt ProfileSuites: MYiniMeterSkins: Earth
User avatar
balala
Rainmeter Sage
Posts: 16267
Joined: October 11th, 2010, 6:27 pm
Location: Gheorgheni, Romania

Re: Sort information in lua

Post by balala »

Yincognito wrote: July 14th, 2023, 9:24 pm Nek deserves the thanks on this one entirely. I only mentioned some "principles" when working with these things, really.
I thank for any kind of information, to both of you.