[Home] [Downloads] [Search] [Help/forum]

Gammon Software Solutions forum

See www.mushclient.com/spam for dealing with forum spam. Please read the MUSHclient FAQ!

[Folder]  Entire forum
-> [Folder]  MUSHclient
. -> [Folder]  Lua
. . -> [Subject]  Sorting tables by heading name

Home  |  Users  |  Search  |  FAQ
Username:
Register forum user name
Password:
Forgotten password?
(New message)
Subject: Sorting tables by heading name
Name:
Your forum user name.
Register forum user name
Password:
Your forum password.
Forgotten password?
Message:
Message to be posted (in English, please).
Forum codes:
Check this if your message uses 'forum codes' or templates (auto-detected for new posts).
Forum codes Templates

Save this message ...


Subject review (reverse sequence)

Pages: 1 2  

Posted by Nick Gammon   Australia  (18,769 posts)  [Biography] bio   Forum Administrator
Date Sun 25 Apr 2010 01:16 AM (UTC)  quote  ]
Message
Ah well that will teach me to not think things through. :-)

I had to revert that change.

Your idea is fine for string keys. However tprint prints generic objects, so the table might consist of (say) functions, strings, booleans, and numbers (as table keys).

It is not meaningful to compare a function to a string, or indeed a function to a function, and thus they can't be sorted.

Your suggested change will only work for a subset of all possible tables.

- Nick Gammon

www.gammon.com.au, www.mushclient.com
[Go to top] top

Posted by Nick Gammon   Australia  (18,769 posts)  [Biography] bio   Forum Administrator
Date Sun 25 Apr 2010 01:07 AM (UTC)  quote  ]

Amended on Sun 25 Apr 2010 01:15 AM (UTC) by Nick Gammon

Message
I don't see a big problem with making that the default (except perhaps, to confuse people because that will now NOT be the order they will get them programmatically) so I have amended the released version.

Commit 039e557. Edit: Reverted.

- Nick Gammon

www.gammon.com.au, www.mushclient.com
[Go to top] top

Posted by Tiopon   USA  (71 posts)  [Biography] bio
Date Sun 25 Apr 2010 12:07 AM (UTC)  quote  ]
Message
One slight change... I did put the 'require "pairsbykeys"' into the code above, so that people who don't realize that they need to enable that as well will still have it working.
[Go to top] top

Posted by Twisol   USA  (2,229 posts)  [Biography] bio
Date Sun 25 Apr 2010 12:04 AM (UTC)  quote  ]
Message
Excellent :)


Nick, I'd actually suggest using pairsByKeys in tprint by default. It's certainly very useful for inspecting tables if you can look at things in a natural order. Otherwise, a tprinta like above would be a welcome addition to tprint.lua.

'Soludra' on Achaea

Blog: http://jonathan.com/
GitHub: http://github.com/Twisol
[Go to top] top

Posted by Tiopon   USA  (71 posts)  [Biography] bio
Date Sat 24 Apr 2010 11:53 PM (UTC)  quote  ]

Amended on Sun 25 Apr 2010 12:06 AM (UTC) by Tiopon

Message
So what I really need is an alias similar to the following...
Quote:
/for j=1,45 do print(j .. ":") for k,v in pairsByKeys(table[j]) do print(" \"" .. k .. "\"\=\"" .. v .. "\"") end end
... Which, at least as I try it now, appears the same as tprint, but is sorted alphabetically...

Easy enough. Copied the tprint function to tprinta and changed the 'value in pairs' to be 'value in pairsByKeys'... everything else the same (well, besides renaming tprint to tprinta everywhere in it so the functions don't fight) and tprinta gives me my nicely sorted lists. :) tprinta follows:
--
--  tprinta.lua

--[[

For debugging what tables have in them, prints recursively

See forum thread:  http://www.gammon.com.au/forum/?id=4903

eg.

require "tprinta"

   tprinta (GetStyleInfo (20))

--]]

require "pairsbykeys"

function tprinta (t, indent, done)
  -- in case we run it standalone
  local Note = Note or print
  local Tell = Tell or io.write
  
  -- show strings differently to distinguish them from numbers
  local function show (val)
    if type (val) == "string" then
      return '"' .. val .. '"'
    else
      return tostring (val)
    end -- if
  end -- show
  -- entry point here
  done = done or {}
  indent = indent or 0
  for key, value in pairsByKeys (t) do
    Tell (string.rep (" ", indent)) -- indent it
    if type (value) == "table" and not done [value] then
      done [value] = true
      Note (show (key), ":");
      tprinta (value, indent + 2, done)
    else
      Tell (show (key), "=")
      print (show (value))
    end
  end
end

return tprinta
[Go to top] top

Posted by Twisol   USA  (2,229 posts)  [Biography] bio
Date Sat 24 Apr 2010 11:48 PM (UTC)  quote  ]

Amended on Sat 24 Apr 2010 11:50 PM (UTC) by Twisol

Message
Incorrect. Every insertion in inherently unsorted as well. This is why this code:

tbl = {}
tbl.a = 1
tbl.b = 2
tbl.c = 3
tprint(tbl)


results in (as just one possibility):

"b": 2
"a": 1
"c": 3


In response to your edit: Yes, that might be it. The order tprint comes up with for a table will always be the same no matter how many times you run it, but once you modify it, that all goes out the window.

'Soludra' on Achaea

Blog: http://jonathan.com/
GitHub: http://github.com/Twisol
[Go to top] top

Posted by Tiopon   USA  (71 posts)  [Biography] bio
Date Sat 24 Apr 2010 11:44 PM (UTC)  quote  ]

Amended on Sat 24 Apr 2010 11:47 PM (UTC) by Tiopon

Message
But if I can display it correctly, I should be able to, instead of making it display, save it to a new table, right? Should be able to do something like (but not exactly):
Quote:
/table2 = {} for j=1,45 do table2[j] = {} for k,v in pairsByKeys(table[j]) do table2[j][k]=v end end


If I have it create a second table, I can then save the second table instead of the first, and next time it loads up the table on a restart I'll have a nicely sorted table (until the next time it updates). Also, I'll be able to use tprint on the second table to have everything nicely indented. :)

Edit: So I suppose using i as my value wasn't the best choice, since it gets grabbed by the code as 'italicize'. Changing the i to j, so it doesn't get snagged.

Or is what you're saying that the code will save in random order based on its current hash, so regardless of any prior sorting, it's not going to be sorted when it's saved? :) Just realized now that might be what you were saying.
[Go to top] top

Posted by Twisol   USA  (2,229 posts)  [Biography] bio
Date Sat 24 Apr 2010 11:37 PM (UTC)  quote  ]

Amended on Sat 24 Apr 2010 11:38 PM (UTC) by Twisol

Message
But see, what you are asking is inherently impossible. You can't reorder non-numeric keys. The order you get pairs from pairs() has no.discernable order, and indeed isn't supposed to have an order. It simply returns the pairs in whatever order it finds them in.

ipairs() only gets around this by literally using a loop starting at 1 and going up to the first nonexistent entry.

'Soludra' on Achaea

Blog: http://jonathan.com/
GitHub: http://github.com/Twisol
[Go to top] top

Posted by Tiopon   USA  (71 posts)  [Biography] bio
Date Sat 24 Apr 2010 11:31 PM (UTC)  quote  ]
Message
Is there a good way to save it into a new table using the pairsByKeys function? If I can save it into a new table, I should be able to use that temporary table to replace the new table when it's done... just parse through the tables twice, once to sort, once to replace. I suppose a third time to wipe the temporary tables.
[Go to top] top

Posted by Nick Gammon   Australia  (18,769 posts)  [Biography] bio   Forum Administrator
Date Sat 24 Apr 2010 11:28 PM (UTC)  quote  ]
Message
You can't "update the original table properly" - if you use named keys for tables in Lua they are stored by hash and therefore retrieved in what seems a random fashion.

Only numeric keys (1, 2, 3 etc) are retrieved in sequential order, and only then if you use ipairs rather than pairs.

The only thing you can do is sort them upon retrieval (which is very fast).

It's not really "messy" - the way the data is stored internally isn't a big concern, the important thing is to present it nicely when required.

- Nick Gammon

www.gammon.com.au, www.mushclient.com
[Go to top] top

Posted by Twisol   USA  (2,229 posts)  [Biography] bio
Date Sat 24 Apr 2010 11:26 PM (UTC)  quote  ]

Amended on Sat 24 Apr 2010 11:29 PM (UTC) by Twisol

Message
I see, I did misunderstand. No, you cannot sort the non-numeric keys in a table. Lua tables are basically hashmaps or associative arrays. Pairs are inherently unsorted, and the only way to actually sort by anything else is exactly what you found: turning a=b into 1={a,b}.

There is generally no reason to sort by key unless you're going to use that order immediately, in which case Nick's solution would work excellently.

'Soludra' on Achaea

Blog: http://jonathan.com/
GitHub: http://github.com/Twisol
[Go to top] top

Posted by Tiopon   USA  (71 posts)  [Biography] bio
Date Sat 24 Apr 2010 11:24 PM (UTC)  quote  ]

Amended on Sat 24 Apr 2010 11:30 PM (UTC) by Tiopon

Message
Heh. Just realized now what Twisol's suggestion did... resorted my table by name and losing its key sorting, which would be fine if the numbers weren't directly related to the table. :p Time to fix 268 rows in Excel... Done.

Ah, thought that pairsByKeys might be the right one... So here's what I did to actually have it display an individual entry:
Quote:
/for k,v in pairsByKeys(table[1]) do print (k,v) end


What I'm not quite sure about is how to get that to update the original table properly and not just display it beautifully... I suppose I can just leave it messy in reality and show it nicely when done, but what do I have to do to make that work... I was trying to come up with a for ipairs that would let me do all the tables, but failing. Now that my table is fixed up again and I have an Excel backup for if I screw it up more with testing, let's see what we can do... heh.

Edit: Twisol, your suggestion would have worked great if I wanted was to change
Quote:
1:
"attack1"="Point"
"finish1"="Handoff"
"level"=1
"name"="Relay"
2:
"attack1"="Clean"
"finish1"="Ringup"
"level"=1
"name"="Busboy"
into
Quote:
1:
"attack1"="Clean"
"finish1"="Ringup"
"level"=1
"name"="Busboy"
2:
"attack1"="Point"
"finish1"="Handoff"
"level"=1
"name"="Relay"
but I was trying to sort the attack1/finish/level/name, not based on the "name" field. :)

So this will display the whole listing... there's 45 subtables under the main one, but if I can make it not be hardcoded that would be nice... be nicer if I can have it update the table itself. :)
Quote:
/for i=1,45 do for k,v in pairsByKeys(table) do print (k,v) end end
[Go to top] top

Posted by Twisol   USA  (2,229 posts)  [Biography] bio
Date Sat 24 Apr 2010 11:04 PM (UTC)  quote  ]

Amended on Sat 24 Apr 2010 11:05 PM (UTC) by Twisol

Message
Tiopon said:

So how exactly how am I supposed to use that... like this?
Quote:
table.sort(table[1], function(t1,t2) return t1.name < t2.name end)
or
Quote:
table.sort(table, function(t1,t2) return t1.name < t2.name end)

Am I supposed to do the table2 thing first? Sorry, it's just not seeming to do anything... I'm just not properly comprehending how the process is working.


The second one. That function you pass to table.sort is called a comparator, and it's called to compare two values within the table, to decide which comes first. In your table, each value is a table itself, and when two of them are compared, they're passed to the comparator. In the comparator, I determine the order based on each one's name,


@Nick: I may have misunderstood Tiopon, but I believe he wants to sort by value, not key.

'Soludra' on Achaea

Blog: http://jonathan.com/
GitHub: http://github.com/Twisol
[Go to top] top

Posted by Nick Gammon   Australia  (18,769 posts)  [Biography] bio   Forum Administrator
Date Sat 24 Apr 2010 10:37 PM (UTC)  quote  ]

Amended on Sat 24 Apr 2010 10:38 PM (UTC) by Nick Gammon

Message
The module pairsbykeys which ships with MUSHclient will do that. Given a table, it iterates through it in the order of the keys (so attack1 would come first):


require "pairsbykeys"

-- This prints the math functions in key order
for k, v in pairsByKeys (math) do
  print (k, v)
end -- for


(Internally it copies the keys into a temporary table, sorts that, and then returns the items one by one).

- Nick Gammon

www.gammon.com.au, www.mushclient.com
[Go to top] top

Posted by Tiopon   USA  (71 posts)  [Biography] bio
Date Sat 24 Apr 2010 10:10 PM (UTC)  quote  ]
Message
So how exactly how am I supposed to use that... like this?
Quote:
table.sort(table[1], function(t1,t2) return t1.name < t2.name end)
or
Quote:
table.sort(table, function(t1,t2) return t1.name < t2.name end)

Am I supposed to do the table2 thing first? Sorry, it's just not seeming to do anything... I'm just not properly comprehending how the process is working.
[Go to top] top

The dates and times for posts above are shown in Universal Co-ordinated Time (UTC).

To show them in your local time you can join the forum, and then set the 'time correction' field in your profile to the number of hours difference between your location and UTC time.


2,364 views.

This is page 1, subject is 2 pages long: 1 2  [Next page]

[Reply to this subject]  Reply to this subject   [New subject]  Start a new subject   [Refresh] Refresh page

Go to topic:           Search the forum


[Go to top] top

[Home]

Written by Nick Gammon - 5K

Comments to: Gammon Software support
[RH click to get RSS URL] Forum RSS feed ( http://www.gammon.com.au/rss/forum.xml )

[Best viewed with any browser - 2K]    [Internet Contents Rating Association (ICRA) - 2K]    [Web site powered by FutureQuest.Net]