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

[LUA Questions] Sorting table contents and Duplicate Search

Started by Loothor, 13 March 2013 - 04:32 PM
Loothor #1
Posted 13 March 2013 - 05:32 PM
Title: [LUA Questions] Sorting table contents and Duplicate Search

Hello,

First off, thanks for the awesome mod and the community that supports it!
Secondly, I do not consider myself a real coder, but I tinker with it until i get it to work usually - So I apologize if I do not understand what you mean - basic explanations may help me more! (Constructive criticism welcome for my code - I am sure it is probably far from good compared to some other programs on here :)/>)

Ok, so onto my issues. I started writing a program for OpenCCSensors to read from a inventory system (that is not started). In the meantime, i have 3 chests next to a sensor for testing. The 2 issues that I am having is I have no idea how to code in a sort feature for my table (to sort in alphabetical order on my screens). Secondly, I found out that my compare option isnt working all of the time. If I spread my items out across the chests, it misses some and doesnt add.

Any ideas? Thanks in advance! (also my apologees for my lack of comments…I need to still work on this best practice!)


function clear() --Clears and sets line to 1,1
term.clear()
term.setCursorPos(1,1)
end
function hasPeripheral(sPeri)
local tSides = redstone.getSides()
for i = 1, #tSides do
  if peripheral.isPresent( tSides[i] ) and peripheral.getType( tSides[i] ) == sPeri then
  peri = tSides[i]
  end
  if peri == "" then
  peri = "Not Present"
  end
end
end
function pullDetail()
local name = ""
local t = {}
local qty = 0
local chests = iSense.getTargets()
local x = 0
for location, basicDetails in pairs(chests) do
chestDetails = iSense.getTargetDetails(location)
for slotNum, slotDetail in pairs(chestDetails.Slots) do
  if slotDetail.Name == "Inventory Sensor Card" then
  else
   if slotDetail.Name == "empty" then
   emptyCount = emptyCount + 1
   else
   name = slotDetail.Name
   qty = slotDetail.Size
   itemDetail[x] = {name, qty}
   x = x + 1
   end
  end
end
end
x = 0
end
function compareTable() -- Compares table and removes duplicates
local x = 0
local y = 0
local z = 0
while itemDetail[x] ~= nil do
compItem = itemDetail[x][1]
compQty = itemDetail[x][2]
z = x + 1
while itemDetail[z] ~= nil do
  if compItem == itemDetail[z][1] then
  itemDetail[x][2] = compQty + itemDetail[z][2]
  table.remove(itemDetail,z)
  end
z = z + 1
end
x = x + 1
end
end
function setupMonitor() -- Sets up the lines
monitor1.clear()
monitor1.setTextScale(0.5)
maxWidth, maxHeight = monitor1.getSize()
maxUsableHeight = maxHeight-4

for i = 1, maxWidth do --Prints vertical lines on screen. - Top and bottom
monitor1.setCursorPos(i,2)
monitor1.write("-")
monitor1.setCursorPos(i,maxHeight-3)
monitor1.write("-")
end

local tVertical = {maxWidth/5*1, maxWidth/5*2, maxWidth/5*3, maxWidth/5*4}
for i = 1, maxUsableHeight do --Prints vertical lines - Divides screen by 5
  for z = 1, #tVertical do
  monitor1.setCursorPos(tVertical[z],i)
  monitor1.write("|")
  end
end

local tItemLabels = {1, maxWidth/5*1+2, maxWidth/5*2+2, maxWidth/5*3+2, maxWidth/5*4+2}
local tQtyLabels = {maxWidth/5*1-9, maxWidth/5*2-9, maxWidth/5*3-9, maxWidth/5*4-9, maxWidth/5*5-7}

for i = 1, #tItemLabels do
monitor1.setCursorPos(tItemLabels[i],1)
monitor1.write("Item")
end
for i = 1, #tQtyLabels do
monitor1.setCursorPos(tQtyLabels[i],1)
monitor1.write("Quantity")
end

end
function displayMonitor() -- Displays the table on the screen
local x = 0
local tItemLabels = {1, maxWidth/5*1+2, maxWidth/5*2+2, maxWidth/5*3+2, maxWidth/5*4+2}
local tQtyLabels = {maxWidth/5*1-7, maxWidth/5*2-7, maxWidth/5*3-7, maxWidth/5*4-7, maxWidth/5*5-7}
while itemDetail[x] ~= nil do -- display on screen
for i = 1, #tItemLabels do
  for h = 3, maxUsableHeight do
   if itemDetail[x] == nil then break end
	monitor1.setCursorPos(tItemLabels[i],h)
	monitor1.write(itemDetail[x][1])
	monitor1.setCursorPos(tQtyLabels[i],h)
	monitor1.write(tostring(itemDetail[x][2]))
	x = x + 1
  end
end
end
monitor1.setCursorPos(1,maxHeight-1)
monitor1.write("Empty Slots: " .. emptyCount)
--print("Empty Slots: " .. emptyCount)
end
os.loadAPI("ocs/apis/sensor")
itemDetail = {}
chestDetails = {}
slotDetail = {}
maxHeight = 0
peri = ""
emptyCount = 0
hasPeripheral("monitor")
monitor1 = peripheral.wrap(peri)
hasPeripheral("sensor")
sensor1 = peri
iSense = sensor.wrap(sensor1)
peri = nil
setupMonitor()
pullDetail()
compareTable()
displayMonitor()
Lyqyd #2
Posted 13 March 2013 - 05:52 PM
Split into new topic.
theoriginalbit #3
Posted 13 March 2013 - 05:58 PM
For the sorting there is a function that can already sort for you in the table api; table.sort you can even supply a custom caparison function.

As for the other issue I had a quick scan and can't see the issue, but im not in the best environment atm to see it and test it (on phone and about to go into a lecture)
Loothor #4
Posted 15 March 2013 - 07:09 AM
Thanks for splitting into a new topic!

(I am also on my phone and may not get to the computer until the weekend. :(/>)

I tried to use the table.sort, but I am not sure I used it correctly.

So, for example my table goes like this:

Table:
Table1: name, qty

I think when I tried the sort function, it sorted on the upper of the tables, effectively doing nothing. Is there a way to sort on the name portion?

My duplicate check is weird…it was working, but if I split cobblestone and scatter it across the chest, it might combine some, but not all. So, not really sure.
Loothor #5
Posted 16 March 2013 - 05:43 PM
Ahha! Took a while but I think i finally figured out how to combine my duplicate items successfully….The issue I was having was it would read the slot, then remove it from the table, thus altering my index. To get around this change in index, I checked my index backwards :)/>


function compareTable() -- Compares table and removes duplicates
local x = 0
while itemDetail[x] ~= nil do
for i = #itemDetail, x + 1, -1 do --backwards to avoid index changes from affecting loop
  if itemDetail[x][1] == itemDetail[i][1] then
  itemDetail[x][2] = itemDetail[x][2] + itemDetail[i][2]
  table.remove(itemDetail,i)
  end
end
x = x + 1
end
end


Unfortunately, I am still trying to sort my "deep table" (nested table?)…Anyone have any ideas? I am trying to sort alphabetically by name (apples, cobblestone, flint).


itemDetail[x] = {name, qty} -- table layout


Kingdaro #6
Posted 16 March 2013 - 06:23 PM
You could pass a function to table.sort.

Pastebinned because it looked ugly.

Where this sorts table elements from least to greatest, or in the case of strings, a to z. If I were to use > instead, the order would be reversed.
theoriginalbit #7
Posted 16 March 2013 - 06:31 PM
Additionally with Lua and < > operators on strings it does the comparison on each char. So when you have 2 strings starting with 'a' it will check the next char, so if you have 'ab' and 'aa' it will sort them correctly.
Loothor #8
Posted 16 March 2013 - 07:27 PM
Wow, thank you guys! It turned out great!

I had to change my x = 0 to x = 1 throughout the program as the sort function would not accept the 0 - for itemDetail[0][1] - it always had the first item of the table not being included in the sort.

I still have a long ways to go before this program is ready for mass inventory readings :)/>, but i'll stick around the forums and hang out with the community!