get key list in descending order in lua scipt - lua

I have one list in redis key store. it's containing date as keyname like this.
key
===
20160429
20160430
20160501
20160502
Now I want to key last 2 keys, for this I am doing following in my lua script.
local data = {};
local keyslist = redis.call('keys', 'stats:day:*');
local key, users, redisData;
-- keyslist = #keyslist.sort(#keyslist, function(a, b) return a[2] > b[2] end);
-- keyslist = #keyslist.sort(#keyslist, function(a,b) if a>b then return true; else return false; end end);
for iCtr = 1, #keyslist do
key = string.gsub(keyslist[iCtr], 'stats:day:','');
redisData = redis.call('hmget', keyslist[iCtr], 'image','video');
table.insert(data, {date=key, imgctr=redisData[1], vidctr=redisData[2]});
if iCtr == 2 then break end
end
but this is returning first 2 records, I need last 2 records (e.g. following keys)
20160501
20160502
How Do I get descending key list?

If I understand you right, you might want to do the following:
local count = 0
for iCtr = #keyslist-1,#keyslist do
count=count+1
--do your stuff
if count == 2 then break end
--or
if iCtr == #keyslist then break end
end
This will start at the penultimate item in the keyslist and then count upwards.
Note, I did not test the code, but it should work..

Sample code for sorting a Lua table:
keylist = {1,2,5,8,3, 5}
-- after the following line keylist will be sorted ascending (default)
table.sort(keylist)
-- this line is equivalent:
table.sort(keylist, function (a,b) return a < b end)
the second parameter is to table.sort is a function that takes two table values and returns true if the first one is smaller than the second one.
To sort a table decending you simply call
table.sort(keylist, function(a,b)return a > b end)
Please keep in mind that you can only use this to sort the table values, not their keys. But as you are using keys in a different context this should solve your problem.

Related

Is it possible to extract the variable from constant in lua [duplicate]

I have this table in lua:
local values={"a", "b", "c"}
is there a way to return the index of the table if a variable equals one the table entries?
say
local onevalue = "a"
how can I get the index of "a" or onevalue in the table without iterating all values?
There is no way to do that without iterating.
If you find yourself needing to do this frequently, consider building an inverse index:
local index={}
for k,v in pairs(values) do
index[v]=k
end
return index["a"]
The accepted answer works, but there is room for improvement:
Why not exit the loop once the element is found? And why bother copying the entire source table into a new throwaway table?
Usually, this sort of function returns the first array index with that value, not an arbitrary array index with that value.
For arrays:
-- Return the first index with the given value (or nil if not found).
function indexOf(array, value)
for i, v in ipairs(array) do
if v == value then
return i
end
end
return nil
end
print(indexOf({'b', 'a', 'a'}, 'a')) -- 2
For hash tables:
-- Return a key with the given value (or nil if not found). If there are
-- multiple keys with that value, the particular key returned is arbitrary.
function keyOf(tbl, value)
for k, v in pairs(tbl) do
if v == value then
return k
end
end
return nil
end
print(keyOf({ a = 1, b = 2 }, 2)) -- 'b'
If you use Lua for Roblox development, you can use the table.find method:
print(table.find({'a', 'b', 'c'}, 'b'))

How to order a Table to tables based on 1 single data part of it?

I am a hobbyest making mods in TableTop Simulator using LUA and have a question that I can not seam to work out.
I have a number of "objects" which is a table in TTS that contains various data for those objects. For example.. obj.position = {x,y,z}... and can be accessed at the axis level as well.
obj.position = {5,10,15} -- x,y,z
obj.position.x == 5
This is an example. The makers of TTS have made it so you can access all the parts like that. So I can acess the object.. and then its various parts. There is a heap, like name, mesh, difuse and a ton more. roations{x,y,z} etc etc
Anyway. I have a table of objects... and would like to order those objects based on the positional data of the x axis.. so highest to lowest. So if I have a table and obj1 in that table is x=3 and obj2 is x=1 and obj3 = x=2 it would be sorted as obj2,obj3,obj1
Pseudo code:
tableOfObjects = {obj1,obj2,obj3}
--[[
tableOfObjectsp[1] == obj1
tableOfObjectsp[2] == obj2
tableOfObjectsp[3] == obj3
tableOfObjectsp[1].position.x == 3
tableOfObjectsp[2].position.x == 1
tableOfObjectsp[4].position.x == 2
--]]
---After Sort it would look this list
tableOfObjects = {obj1,obj3,obj2}
--[[
tableOfObjectsp[1] == obj1
tableOfObjectsp[2] == obj3
tableOfObjectsp[3] == obj2
tableOfObjectsp[1].position.x == 3
tableOfObjectsp[2].position.x == 2
tableOfObjectsp[3].position.x == 1
--]]
I hope I am making sense. I am self taught in the last few months!
So basically I have a table of objects and want to sort the objects in that table based on a single value attached to each individual object in the table. In this case the obj.position.x
Thanks!
You need table.sort. The first argument is the table to sort, the second is a function to compare items.
Example:
t = {
{str = 42, dex = 10, wis = 100},
{str = 18, dex = 30, wis = 5}
}
table.sort(t, function (k1, k2)
return k1.str < k2.str
end)
This article has more information
table.sort(tableOfObjects, function(a, b) return a.position.x > b.position.x end)
This line will sort your table tableOfObjects in descending order by the x-coordinate.
To reverse order, replace > by <.
From the Lua reference manual:
table.sort (list [, comp])
Sorts list elements in a given order, in-place, from list[1] to
list[#list]. If comp is given, then it must be a function that
receives two list elements and returns true when the first element
must come before the second in the final order (so that, after the
sort, i < j implies not comp(list[j],list[i])). If comp is not given,
then the standard Lua operator < is used instead.
Note that the comp function must define a strict partial order over
the elements in the list; that is, it must be asymmetric and
transitive. Otherwise, no valid sort may be possible.
The sort algorithm is not stable: elements considered equal by the
given order may have their relative positions changed by the sort.
So in other words table.sort will sort a table in ascending order by its values.
If you want to order descending or by something other than the table value (like the x-coordinate of your table value's position in your case) you have to provide a function that tells Lua which element will come first.
you can create a function that handles this exact thing:
local function fix_table(t)
local x_data = {};
local inds = {};
local rt = {};
for i = 1, #t do
x_data[#x_data + 1] = t[i].position.x;
inds[t[i].position.x] = t[i];
end
local min_index = math.min(table.unpack(x_data));
local max_index = math.max(table.unpack(x_data));
for i = min_index, max_index do
if inds[i] ~= nil then
rt[#rt + 1] = inds[i];
end
end
return rt;
end
local mytable = {obj1, obj2, obj3};
mytable = fix_table(mytable);
fix_table first takes in every x value inside of the given table, and also places a new index inside the table inds according to each x value (so that they will be ordered from least to greatest), then it gets the smallest value in the x_data array table, which is used to traverse the inds table in order. fix_table checks to make sure that inds[i] is not equal to nil before it increases the size of the return table rt so that every value in rt is ordered from greatest to least, starting at index 1, and ending at index #rt, finally rt is returned.
I hope this helped.

Is it possible to make an iterator in Lua that can iterate over a dictionary?

Lets say that I have a dictionary in Lua (i.e. a Lua table that contains indexes of type string) like so:
local my_dictionary = {a = 123; b = 321; c = 456; d = 654};
What I am trying to do is create an iterator function that can iterate over a table even if its indexes are of type string; kind of like pairs, however whenever I try to call next() to get the next index,value it will only return the index,value if the index is of type int. An idea I had was maybe to call (index):byte(1, -1) and add up the tuple of ints, and use that as a sort of pretend index, just to keep track of the indexes, but I do not think that would work with next. Here is basically what I have so far:
local function each(list)
if #list > 0 then
local function my_itr(lst, ind)
return next(lst, ind);
end
return my_itr, List, 0;
end
return function() end, nil, nil;
end
this only works for a table with int indexes (an array table), so I was wondering if anyone could help me out.
Thanks.
Edit: To make this less vague here is an example piece of code of what I am trying to accomplish:
local mytable = {a = 123; b = 321; 3, 2, 1, c = "bca"};
for i,v in each(mytable) do
print(i,v);
end
what it should output:
>a 123
>b 321
>1 3
>2 2
>3 1
>c bca
The output would not have to be in exact order.
It should work exactly as you want it to with a couple of tweaks: fix typo in List and pass nil instead of 0:
local function each(list)
local function my_itr(lst, ind)
return next(lst, ind)
end
return my_itr, list, nil
end
local mytable = {a = 123; b = 321; 3, 2, 1, c = "bca"}
for i,v in each(mytable) do
print(i,v)
end
This prints the following for me, which is what you'd need:
1 3
2 2
3 1
a 123
b 321
c bca
You can achieve this very behavior by using pairs. Don't confuse it with ipairs though - these are two different table traversal functions!
While ipairs only traverses integer keys of the table (usually it also stops at the first non-existent integer key), pairs traverses all key-value pairs in the table.
So, by writing
local mytable = {a = 123; b = 321; 3, 2, 1, c = "bca"};
for i, v in pairs(mytable) do
print(i, v);
end
You'll get all key-value pairs printed, in some random order. Here's the demo.
As a sidenote, there's no such thing as 'dictionary' in Lua - all associative arrays are referred to as 'tables'.

how to represent nil in a table

Let's suppose I want to store a list of element. Including some nil values. The position of the values is significant, and I need to represent the absence of a value in the list at a given position.
Here is a problem:
a = {1,2,3,nil,4}
for k,v in ipairs(a) do
print(k,v)
end
print(a[4])
print(a[5])
The for loop will only print elements 1,2 and 3. It stops at nil. The first print statement prints nil, but I'm not sure if it is actually stored in the table or not. (Who knows?) The second print statement prints 4 - as expected.
So here is the question: how to represent a list of elements in a table, and iterate through them efficiently? Given the conditions above, e.g. the position is significant, and some of the positions are "empty". In other words: have no value, but the absence of that value at that position has a meaning.
This is module "null.lua"
local function null(...)
local t, n = {...}, select('#', ...)
for k = 1, n do
local v = t[k]
if v == null then t[k] = nil
elseif v == nil then t[k] = null
end
end
return (table.unpack or unpack)(t, 1, n)
end
_G.null = null
Use null() as encoder and decoder
require("null")
a = {null(1,2,3,nil,4)}
-- the same could be done element-by-element
-- a = {null(1),null(2),null(3),null(nil),null(4)}
for k,v in ipairs(a) do
v = null(v)
print(k,v)
end
print(null(a[4]))
print(null(a[5]))
Lua tables can be used to create any Abstract Data Structure, in your case you indicated that you want a "list". A Lua table is a data structure that combines numeric index based access with key:value access.
Based on your example, you are using the numeric index feature of tables that let you iterate (with ipairs()) through those values. You will not be able to put nil into the table since the numeric index stops at the first nil entry. The remaining values in the table are stored as key:value pairs.
There are several work-arounds, but it depends on why you want a nil in the list. The simplest approach is to use the string "nil" rather than the native data type nil.
a = {1, 2, 3, "nil", 4}
for k,v in ipairs(a) do
print(k,v)
end
The result of this code is:
1 1
2 2
3 3
4 nil
5 4
Because of the way Lua implements strings, there is not a performance penalty for comparing to the string "nil" versus comparing to the native type nil.
The issue of "holes" (caused by nil) in an array are discussed in Programming in Lua, Chapter 5 Tables. Roberto Ierusalimschy recommendation is to track the size of the array to avoid problems with holes.
The following code shows an Object Oriented approach to tracking the size of the list. There are many possible variations on this theme.
function makeList(...)
local list = table.pack(...)
list.length =
function(self) return self.n
end
list.append =
function(self, value)
self.n = self.n + 1
self[self.n] = value
end
list.print =
function(self)
for i = 1, self.n do print(i, self[i]) end
end
return list
end
a = makeList(1, 2, 3, nil, 4)
a:append(5)
a:print()
print(a:length())
The result is:
1 1
2 2
3 3
4 nil
5 4
6 5
6
Note that the function table.pack creates a field 'n' which contains the correct number of items even when 'nil' is present. See PIL chapter 6.2, Variadic Functions for a complete explanation.
Don't just hack something together, write your own datastructure for this. If you "overload" ipairs (by writing an appropriate iterator) you can use it as a table:
function create(...)
local t = table.pack(...)
local self = {
num = t.n,
elements = { ... }
}
return self
end
function elements(t)
local f = function(s, i)
i = i + 1
if i <= s.num then
return i, s.elements[i]
end
end
return f, t, 0
end
local seq = create(1, 2, nil, 3)
print(seq.num)
for i, e in elements(seq) do
print(i, e)
end
-- results:
-- 4
-- 1 1
-- 2 2
-- 3 nil
-- 4 3
You could know define a metatable for this structure and have it use its own ipairs, so you don't even have to change the name.
Well, you can't store nil in the table without issues.
The most simple solution here would be to introduce your own unique value.
local mynil = {} -- every new table is unique!
a = {1,2,3,mynil,4}
for k,v in ipairs(a) do
if (v == mynil) then
v = nil
end
print(k,v)
end
No more issues with "nil" string that might be stored in the table as well, the minor issue is one more comparison. ipairs or any other iterator will show that the key with mynil value exists. That means you can separate mynil key existence with missing key =nil.
P.S. If you want to shift your list, you may consider table.remove(list, key) function.
The answer to this is rather simple, and these "workaround a" suggested is definitely overkill. Just keep track of the number of items in your table whenever it's changed (note: do not use #, you have too keep track manually to deal with nil values) and use a numeric for loop to iterate over it.

How to pop/remove the next item (any) in a key-value-pair table in Lua?

In Lua how would one pop/remove the next item (any order) in a key-value-pair table?
Is this possible without having to iterate using pairs?
There is a primitive function next, you can call next(t,k), where k is a key of the table t, returns a next key in the table, in an arbitrary order, and the value associated with this key.
If k is nil, next(t,k) returns the first element if there is one. So you can iterate the table from calling next(t,nil) and end when the next key is nil.
This is an simple example to demonstrate the use of next:
local t = {a = "va", b = "vb", c = "vc"}
local k,v = next(t,nil)
print(k,v)
k,v = next(t,k)
print(k,v)
k,v = next(t,k)
print(k,v)
k,v = next(t,k)
print(k,v)
Output:
a va
c vc
b vb
nil nil
The global function next is useful here. The docs explain it pretty well in general. To use it iteratively, this is 'key':
You may ... modify existing fields. In particular, you may clear
existing fields.
A simple pop function:
-- removes and returns an arbitrary key-value pair from a table, otherwise nil
local pop = function (t)
local key, value = next(t)
if key ~= nil then
t[key] = nil
end
return key, value
end
Demo:
local test = { "one", c = "see", "two", a = "ayy", b = "bee", "three" }
assert(next(test), "Table was expected to be non-empty")
local key, value = pop(test)
while key do
print(key, value)
key, value = pop(test)
end
assert(not next(test), "Table was expected to be empty")
If you run the demo multiple times, you might see the arbitrariness of the table sequence.

Resources