Sorting a Lua table by key - sorting

I have gone through many questions and Google results but couldn't find the solution.
I am trying to sort a table using table.sort function in Lua but I can't figure out how to use it.
I have a table that has keys as random numeric values. I want to sort them in ascending order. I have gone through the Lua wiki page also but table.sort only works with the table values.
t = { [223]="asd", [23]="fgh", [543]="hjk", [7]="qwe" }
I want it like:
t = { [7]="qwe", [23]="fgh", [223]="asd", [543]="hjk" }

You cannot set the order in which the elements are retrieved from the hash (which is what your table is) using pairs. You need to get the keys from that table, sort the keys as its own table, and then use those sorted keys to retrieve the values from your original table:
local t = { [223]="asd", [23]="fgh", [543]="hjk", [7]="qwe" }
local tkeys = {}
-- populate the table that holds the keys
for k in pairs(t) do table.insert(tkeys, k) end
-- sort the keys
table.sort(tkeys)
-- use the keys to retrieve the values in the sorted order
for _, k in ipairs(tkeys) do print(k, t[k]) end
This will print
7 qwe
23 fgh
223 asd
543 hjk
Another option would be to provide your own iterator instead of pairs to iterate the table in the order you need, but the sorting of the keys may be simple enough for your needs.

What was said by #lhf is true, your lua table holds its contents in whatever order the implementation finds feasible. However, if you want to print (or iterate over it) in a sorted manner, it is possible (so you can compare it element by element). To achieve this, you can do it in the following way
for key, value in orderedPairs(mytable) do
print(string.format("%s:%s", key, value))
end
Unfortunately, orderedPairs is not provided as a part of lua, you can copy the implementation from here though.

The Lua sort docs provide a good solution
local function pairsByKeys (t, f)
local a = {}
for n in pairs(t) do table.insert(a, n) end
table.sort(a, f)
local i = 0 -- iterator variable
local iter = function () -- iterator function
i = i + 1
if a[i] == nil then return nil
else return a[i], t[a[i]]
end
end
return iter
end
Then you traverse the sorted structure
local t = { b=1, a=2, z=55, c=0, qa=53, x=8, d=7 }
for key,value in pairsByKeys(t) do
print(" " .. tostring(key) .. "=" .. tostring(value))
end

There is no notion of order in Lua tables: they are just sets of key-value pairs.
The two tables below have exactly the same contents because they contain exactly the same pairs:
t = { [223] = "asd" ,[23] = "fgh",[543]="hjk",[7]="qwe"}
t = {[7]="qwe",[23] = "fgh",[223] = "asd" ,[543]="hjk"}

Related

Sorting multidimensional table in Lua

The "how to sort a table in Lua" question isn't new, but the answers I found can't help me out, maybe you can.
I got this Table:
table = {} -- some kind of database
table[1] = {table.containing.table.with.even.more.tables.inside}
table[9] = {table.containing.table.with.even.more.tables.inside}
table[13] = {table.containing.table.with.even.more.tables.inside}
table[15] = {table.containing.table.with.even.more.tables.inside}
table[45] = {table.containing.table.with.even.more.tables.inside}
table[3254] = {table.containing.table.with.even.more.tables.inside}
Now I want to iterate through "table", check for an specified boolean it contains and if so, run a method with parameters from some subtabels.
for key, value in pairs(table) do
print(key)
end
Is something like:
9 13 1 3254 45 15
As far as I know, that's because Lua iterates through hashvalues(right?).
My Idea was:
sorted_table = {} -- shall point to table, with sorted keys
for i = 0, #table do -- from 0 to the last key of table (some write #table is the last key, some write it's the number of contained keys, I don't know. If you do, please tell me.)
if table[i] then -- for runs every number from i to #table, if i is a key, bingo.
table.insert(sorted_table,(table[i])) -- first key found -> sorted_table[1], second -> sorted_table[2]....
end
end
for k,v in pairs(sorted_table) do
print(key)
end
I got no error, it just jumps over the function and nothing happens. When I print #table, it prints 0. #table is in another file but it's not local but used at other location in the functionfile, so,.. this is weird.
EDIT
Mh strange. I threw some debugs, #table is nil, but in a pairs(table) just under the code, everything works fine.
**SOLUTION-EDIT**
local sorted_table = {}
for k, v in pairs(original_table) do
table.insert(sorted_table, k)
end
table.sort(sorted_table)
for k, v in ipairs(sorted_table) do
print(original_table[v])
end
A little try of explanation:
#table does not necessarily return the length of a table. A table element gets a default key if added in a table without a special key. These keys start from 1 and go up to n. If there is a gap between two keys, when you give your own key, #table will return the key right before that gap.
Example:
t = {'one', 'two', 'three'} -- would be a table like 1 - one, 2 - two, 3 - three
print(#t) -- the last key -> 3, here it works
t2 = {'one', 'two', [4] = 'four'} -- would be a table like 1 - one, 2 - two, 4 - four
print(#t2) -- the last key without a gap -> 2, does not work
Same with pairs(table) and ipairs(table). ipairs iterates from key 1 to n without a gap, pairs iterates over all keys. That's why the solution works.
You can set an own metamethod for the table (__len) to use # for the right length.
And remember that your table keys start at 1 by default.
Hope it helped a bit to unterstand the problem here.
SOLUTION
local sorted_table = {}
for k, v in pairs(original_table) do
table.insert(sorted_table, k)
end
table.sort(sorted_table)
for k, v in ipairs(sorted_table) do
print(original_table[v])
end

How to create the equivalent of a HashMap<Int, Int[]> in Lua

I would like to have a simple data structure in lua resembling a Java HashMap equivalent.
The purpose of this is that I wish to maintain a unique key 'userID' mapped against a set of two values which get constantly updated, for example;
'77777', {254, 24992}
Any suggestions as to how can I achieve this?
-- Individual Aggregations
local dictionary = ?
-- Other Vars
local sumCount = 0
local sumSize = 0
local matches = redis.call(KEYS, query)
for _,key in ipairs(matches) do
local val = redis.call(GET, key)
local count, size = val:match(([^:]+):([^:]+))
topUsers(string.sub(key, 11, 15), sumCount, sumSize)
-- Global Count and Size for the Query
sumCount = sumCount + tonumber(count)
sumSize = sumSize + tonumber(size)
end
local result = string.format(%s:%s, sumCount, sumSize)
return result;
-- Users Total Data Aggregations
function topUsers()
-- Do sums for each user
end
Assuming that dictionary is what you are asking about:
local dictionary = {
['77777'] = {254, 24992},
['88888'] = {253, 24991},
['99999'] = {252, 24990},
}
The tricky part is that the key is a string that can't be converted to a Lua variable name so you must surround each key with []. I can't find a clear description of rule for this in Lua 5.1 reference manual, but the Lua wiki says that if a key "consists of underscores, letters, and numbers, but doesn't start with a number" only then does it not require the [] when defined in the above manner, otherwise the square brackets are required.
Just use a Lua table indexed by userID and with values another Lua table with two entries:
T['77777']={254, 24992}
This is possible implementation of the solution.
local usersTable = {}
function topUsers(key, count, size)
if usersTable[key] then
usersTable[key][1] = usersTable[key][1] + count
usersTable[key][2] = usersTable[key][2] + size
else
usersTable[key] = {count, size}
end
end
function printTable(t)
for key,value in pairs(t) do
print(key, value[1], value[2])
end
end

Python: Sorting a dictionary's values whose values are lists of tuples?

I would like to sort a dictionary where I have a string key but my values are lists of tuples. For example, imagine we have a dictionary where each person is mapped to their rating of different academic subjects, where d.items() would return:
('Person':[("Math",5),("Chemistry",10),("History",2)])
Is there any way I can sort the value of each key alphabetically? For example, d['Person'] would now return:
('Person':[(Chemistry",10),("History",2),("Math",5)])
My solution:
arr = {
'Person': [("Math",5),("Chemistry",10),("History",2)]
}
def customKey(a):
return a[0]
for i in arr.keys():
arr[i] = sorted(arr[i], key=customKey)
print arr

Associatively sorting a table by value in Lua

I have a key => value table I'd like to sort in Lua. The keys are all integers, but aren't consecutive (and have meaning). Lua's only sort function appears to be table.sort, which treats tables as simple arrays, discarding the original keys and their association with particular items. Instead, I'd essentially like to be able to use PHP's asort() function.
What I have:
items = {
[1004] = "foo",
[1234] = "bar",
[3188] = "baz",
[7007] = "quux",
}
What I want after the sort operation:
items = {
[1234] = "bar",
[3188] = "baz",
[1004] = "foo",
[7007] = "quux",
}
Any ideas?
Edit: Based on answers, I'm going to assume that it's simply an odd quirk of the particular embedded Lua interpreter I'm working with, but in all of my tests, pairs() always returns table items in the order in which they were added to the table. (i.e. the two above declarations would iterate differently).
Unfortunately, because that isn't normal behavior, it looks like I can't get what I need; Lua doesn't have the necessary tools built-in (of course) and the embedded environment is too limited for me to work around it.
Still, thanks for your help, all!
You seem to misunderstand something. What you have here is a associative array. Associative arrays have no explicit order on them, e.g. it's only the internal representation (usually sorted) that orders them.
In short -- in Lua, both of the arrays you posted are the same.
What you would want instead, is such a representation:
items = {
{1004, "foo"},
{1234, "bar"},
{3188, "baz"},
{7007, "quux"},
}
While you can't get them by index now (they are indexed 1, 2, 3, 4, but you can create another index array), you can sort them using table.sort.
A sorting function would be then:
function compare(a,b)
return a[1] < b[1]
end
table.sort(items, compare)
As Komel said, you're dealing with associative arrays, which have no guaranteed ordering.
If you want key ordering based on its associated value while also preserving associative array functionality, you can do something like this:
function getKeysSortedByValue(tbl, sortFunction)
local keys = {}
for key in pairs(tbl) do
table.insert(keys, key)
end
table.sort(keys, function(a, b)
return sortFunction(tbl[a], tbl[b])
end)
return keys
end
items = {
[1004] = "foo",
[1234] = "bar",
[3188] = "baz",
[7007] = "quux",
}
local sortedKeys = getKeysSortedByValue(items, function(a, b) return a < b end)
sortedKeys is {1234,3188,1004,7007}, and you can access your data like so:
for _, key in ipairs(sortedKeys) do
print(key, items[key])
end
result:
1234 bar
3188 baz
1004 foo
7007 quux
hmm, missed the part about not being able to control the iteration. there
But in lua there is usually always a way.
http://lua-users.org/wiki/OrderedAssociativeTable
Thats a start. Now you would need to replace the pairs() that the library uses. That could be a simples as pairs=my_pairs. You could then use the solution in the link above
PHP arrays are different from Lua tables.
A PHP array may have an ordered list of key-value pairs.
A Lua table always contains an unordered set of key-value pairs.
A Lua table acts as an array when a programmer chooses to use integers 1, 2, 3, ... as keys. The language syntax and standard library functions, like table.sort offer special support for tables with consecutive-integer keys.
So, if you want to emulate a PHP array, you'll have to represent it using list of key-value pairs, which is really a table of tables, but it's more helpful to think of it as a list of key-value pairs. Pass a custom "less-than" function to table.sort and you'll be all set.
N.B. Lua allows you to mix consecutive-integer keys with any other kinds of keys in the same table—and the representation is efficient. I use this feature sometimes, usually to tag an array with a few pieces of metadata.
Coming to this a few months later, with the same query. The recommended answer seemed to pinpoint the gap between what was required and how this looks in LUA, but it didn't get me what I was after exactly :- which was a Hash sorted by Key.
The first three functions on this page DID however : http://lua-users.org/wiki/SortedIteration
I did a brief bit of Lua coding a couple of years ago but I'm no longer fluent in it.
When faced with a similar problem, I copied my array to another array with keys and values reversed, then used sort on the new array.
I wasn't aware of a possibility to sort the array using the method Kornel Kisielewicz recommends.
The proposed compare function works but only if the values in the first column are unique.
Here is a bit enhanced compare function to ensure, if the values of a actual column equals, it takes values from next column to evaluate...
With {1234, "baam"} < {1234, "bar"} to be true the items the array containing "baam" will be inserted before the array containing the "bar".
local items = {
{1004, "foo"},
{1234, "bar"},
{1234, "baam"},
{3188, "baz"},
{7007, "quux"},
}
local function compare(a, b)
for inx = 1, #a do
-- print("A " .. inx .. " " .. a[inx])
-- print("B " .. inx .. " " .. b[inx])
if a[inx] == b[inx] and a[inx + 1] < b[inx + 1] then
return true
elseif a[inx] ~= b[inx] and a[inx] < b[inx] == true then
return true
else
return false
end
end
return false
end
table.sort(items,compare)

Can't sort table with associative indexes

Why I can't use table.sort to sort tables with associative indexes?
In general, Lua tables are pure associative arrays. There is no "natural" order other than the as a side effect of the particular hash table implementation used in the Lua core. This makes sense because values of any Lua data type (other than nil) can be used as both keys and values; but only strings and numbers have any kind of sensible ordering, and then only between values of like type.
For example, what should the sorted order of this table be:
unsortable = {
answer=42,
true="Beauty",
[function() return 17 end] = function() return 42 end,
[math.pi] = "pi",
[ {} ] = {},
12, 11, 10, 9, 8
}
It has one string key, one boolean key, one function key, one non-integral key, one table key, and five integer keys. Should the function sort ahead of the string? How do you compare the string to a number? Where should the table sort? And what about userdata and thread values which don't happen to appear in this table?
By convention, values indexed by sequential integers beginning with 1 are commonly used as lists. Several functions and common idioms follow this convention, and table.sort is one example. Functions that operate over lists usually ignore any values stored at keys that are not part of the list. Again, table.sort is an example: it sorts only those elements that are stored at keys that are part of the list.
Another example is the # operator. For the above table, #unsortable is 5 because unsortable[5] ~= nil and unsortable[6] == nil. Notice that the value stored at the numeric index math.pi is not counted even though pi is between 3 and 4 because it is not an integer. Furthermore, none of the other non-integer keys are counted either. This means that a simple for loop can iterate over the entire list:
for i in 1,#unsortable do
print(i,unsortable[i])
end
Although that is often written as
for i,v in ipairs(unsortable) do
print(i,v)
end
In short, Lua tables are unordered collections of values, each indexed by a key; but there is a special convention for sequential integer keys beginning at 1.
Edit: For the special case of non-integral keys with a suitable partial ordering, there is a work-around involving a separate index table. The described content of tables keyed by string values is a suitable example for this trick.
First, collect the keys in a new table, in the form of a list. That is, make a table indexed by consecutive integers beginning at 1 with keys as values and sort that. Then, use that index to iterate over the original table in the desired order.
For example, here is foreachinorder(), which uses this technique to iterate over all values of a table, calling a function for each key/value pair, in an order determined by a comparison function.
function foreachinorder(t, f, cmp)
-- first extract a list of the keys from t
local keys = {}
for k,_ in pairs(t) do
keys[#keys+1] = k
end
-- sort the keys according to the function cmp. If cmp
-- is omitted, table.sort() defaults to the < operator
table.sort(keys,cmp)
-- finally, loop over the keys in sorted order, and operate
-- on elements of t
for _,k in ipairs(keys) do
f(k,t[k])
end
end
It constructs an index, sorts it with table.sort(), then loops over each element in the sorted index and calls the function f for each one. The function f is passed the key and value. The sort order is determined by an optional comparison function which is passed to table.sort. It is called with two elements to compare (the keys to the table t in this case) and must return true if the first is less than the second. If omitted, table.sort uses the built-in < operator.
For example, given the following table:
t1 = {
a = 1,
b = 2,
c = 3,
}
then foreachinorder(t1,print) prints:
a 1
b 2
c 3
and foreachinorder(t1,print,function(a,b) return a>b end) prints:
c 3
b 2
a 1
You can only sort tables with consecutive integer keys starting at 1, i.e., lists. If you have another table of key-value pairs, you can make a list of pairs and sort that:
function sortpairs(t, lt)
local u = { }
for k, v in pairs(t) do table.insert(u, { key = k, value = v }) end
table.sort(u, lt)
return u
end
Of course this is useful only if you provide a custom ordering (lt) which expects as arguments key/value pairs.
This issue is discussed at greater length in a related question about sorting Lua tables.
Because they don't have any order in the first place. It's like trying to sort a garbage bag full of bananas.

Resources