This is a read-only snapshot of the ComputerCraft forums, taken in April 2020.
DjTranceFire's profile picture

Sort alphabetically

Started by DjTranceFire, 17 January 2015 - 01:01 PM
DjTranceFire #1
Posted 17 January 2015 - 02:01 PM
Hey there.
Because it seems like i cant get any existing essentia refill system working, i decided to try to build it.
I'm new to all that lua stuff and i'm still learning so please be kind with me and dont judge me for my chaotic code. (Maybe someone can give me some tipps instead?)
This is what my project currently looks like:
Spoiler

This is my current script:

Spoiler

local essentia = {}
local jars = peripheral.getNames()
local m = peripheral.find("monitor")

function firstToUpper(str)
	return (str:gsub("^%l", string.upper))
end

function scanEssentia()
	local x = 1
	local y = 3
	m.clear()
	m.setCursorPos(15,1)
	m.setTextColor(colors.white)
	m.write("Essentia Overview System")
	m.setCursorPos(1,2)
	m.write("--------------------------------------------------")
	m.setCursorPos(1,19)
	m.write("--------------------------------------------------")
	m.setCursorPos(x,y)
	
	for i,j in ipairs(jars) do
		if peripheral.getType(j) == "tt_aspectContainer" then
			asp = peripheral.call(j, "getAspects")
			if (asp[1] ~= nill) then
				for k,v in pairs(asp) do
					m.setCursorPos(x,y)
					asp = string.lower(asp[1])
					countasp = peripheral.call(j, "getAspectCount", asp)
					if countasp == 0 then m.setTextColor(colors.gray) end
					if countasp > 0 and countasp <= 20 then m.setTextColor(colors.red) end
					if countasp < 40 and countasp > 20 then m.setTextColor(colors.yellow) end
					if countasp >= 40 then m.setTextColor(colors.green) end
					m.write(firstToUpper(asp))
					if countasp >= 10 then m.setCursorPos(x+14,y)
					else m.setCursorPos(x+15,y) end
					m.write(tostring(countasp).."  ")
					if y < 18 then
						y = y+1
					else
						y = 3
						x = x+17
					end
				end
			end
		end
	end
end

function monitorEssentia()
	while true do		
		scanEssentia()
		sleep(5)
	end
end

monitorEssentia()


For now it only reads all the jars and prints the output on the monitor.
Everytime i start the script it sorts all the essentia in a different order.
I think it would be much easier to find the correct essentia when everything would be alphabetically.
Is there any way to sort all the essentia based on my code alphabetically?
If not, what would i have to change to do it?

Sorry for my bad english, i hope its not to hard to understand.
Edited on 17 January 2015 - 01:02 PM
KingofGamesYami #2
Posted 17 January 2015 - 02:09 PM
You could do this with a couple of tables, something like this:


local ess_names = {}
local ess_values = {}

--#bla bla bla stuff
ess_names[ #ess_names + 1 ] = asp
ess_values[ asp ] = countasp

--#after everythings found
table.sort( ess_names )
--#now we can render it
for _, name in ipairs( ess_names ) do
  local value = ess_values[ name ]
  local asp = firstToUpper( name )
  --#bla bla bla writing stuff
end
InDieTasten #3
Posted 17 January 2015 - 02:10 PM
Looks cool.

Very nice for a beginner.

As a tip, I would devide your program into different pieces.
One to retrieve the information and store it in like a table or something.
And another piece which will display it.

Devided, your program is much easier to maintain.

Your loop would be much cleaner:

while(true) do
	local current = scanEssentia()
	displayEssentia(current)
	sleep(5)
end
Edited on 17 January 2015 - 01:11 PM
Lignum #4
Posted 17 January 2015 - 02:14 PM
You can use table.sort (it's explained somewhere here) to do this.


local unsorted = {
   "Lorem",
   "ipsum",
   "dolor",
   "sit",
   "amet"
}

table.sort(unsorted, function(a, B)/> --# <-- The forums keep messing this up, you should be able to figure out yourself what this is supposed to be.
   local _a = a:lower() --# We don't want uppercase letters coming first.
   local _b = b:lower() --# So make everything temporarily lowercase to fix it...

   --# If a character's ASCII code is less than the other's, it comes first alphabetically.
   --# See http://asciitable.com
   --#
   --# So, take the first character in the string and compare the ASCII values.
   return string.byte(_a:sub(1,1)) < string.byte(_b:sub(1,1))
end)

print(textutils.serialise(unsorted))
Edited on 17 January 2015 - 01:18 PM
Exerro #5
Posted 17 January 2015 - 03:22 PM
That won't take into account that some strings can start with the same letter. Using table.sort() is the way to go, but make sure to check every character in the corresponding strings until one char is different from the other.


local function compstring( a, b ) -- returns a > b
   a, b = a:lower(), b:lower()
   for i = 1, math.min( #a, #b ) do
      if a:byte(i) > b:byte(i) then return true end
      if a:byte(i) < b:byte(i) then return false end
   end
   return #a > #b
end
table.sort( t, compstring )

I think that should work (provided you have a table of strings) although it may sort it Z-A instead of A-Z. It's easy enough to fix if so.
Edited on 17 January 2015 - 02:24 PM
InDieTasten #6
Posted 17 January 2015 - 03:29 PM
That won't take into account that some strings can start with the same letter. Using table.sort() is the way to go, but make sure to check every character in the corresponding strings until one char is different from the other.


local function compstring( a, b ) -- returns a > b
   a, b = a:lower(), b:lower()
   for i = 1, math.min( #a, #b ) do
	  if a:byte(i) > b:byte(i) then return true end
	  if a:byte(i) < b:byte(i) then return false end
   end
   return #a > #b
end
table.sort( t, compstring )

I think that should work (provided you have a table of strings) although it may sort it Z-A instead of A-Z. It's easy enough to fix if so.

it does ;)/> just flip the return booleans
Lyqyd #7
Posted 17 January 2015 - 06:48 PM
You don't need a custom function for sorting strings alphabetically, if I recall correctly.
Bomb Bloke #8
Posted 17 January 2015 - 10:53 PM
You do if you want it to handle case correctly, unfortunately. Otherwise it decides that A comes after z, or some such rubbish.

But it needn't be so complex. Personally I use:

table.sort(myTable, function (a, b) return string.lower(a) < string.lower(b) end)

Of course, for the OP's use case - where all strings stick to uniform capitalisation - table.sort(myTable) would be entirely sufficient.
Edited on 17 January 2015 - 09:58 PM