Redis: Lua script to return every other nth element of a sorted set - lua

I am trying to put together a lua script to be called from Redis (via an EVAL call) in order to return every other nth element of a sorted set (nth being the rank in the set, not the score).
There are very few online examples of Lua scripts that can be used to build upon, would anyone be able to point me in the right direction?

local function copyNOtherElements(table, interval, startpos)
local elemno = 1
local rettab = {}
for k, v in ipairs(table) do
if k >= startpos and (k - startpos) % interval == 0 then
rettab[elemno] = v
elemno = elemno + 1
end
end
return rettab
end
Sorry about formatting, typing on a phone. that's assuming the table is a 1 based array

For future readers, adding Redis into the previous answer, and a bit more efficient code to iterate the Nth elements:
local function zrange_pick(zset_key, step, start, stop)
-- The next four lines can be removed along with the start/stop params if not needed as in OP Q.
if start == nil than
start = 0
if end == nil than
end = -1
local set_by_score = redis.call('ZRANGE', zset_key, start, end)
local result = {}
for n = 1, #set_by_score, step do
table.insert(result, set_by_score[n])
end
return result
end

Related

/Lua/ How to do this (idk how to call that lol)

I need to make a trolleybus number, which won't repeat for game. For example, there is a number "101" and there musn't be more "101". How to do that? I have a code, but I know, he won't work and I won't test it lol
function giveNumber()
local number = math.random(100, 199)
local takedNumbers = {}
local i = 0
local massiv = i+1
script.Parent.pered.SurfaceGui.TextLabel.Text = number
script.Parent.zad.SurfaceGui.TextLabel.Text = number
script.Parent.levo.SurfaceGui.TextLabel.Text = number
script.Parent.pravo.SurfaceGui.TextLabel.Text = number
takedNumbers[massiv] = {number}
end
script.Parent.Script:giveNumber() // what I wrote here? idk...
if number == takedNumbers[massiv] then
giveNumber()
end
i didn't test it, because I think it won't work because this code is something bad
I think this will serve your needs.
In the function generateUniqueNumber, the script loops until it found a number that is not yet in the array. (in other words, that it hasn't given out yet)
Once it found that number, it will insert it into the table to remember that it has given it out, and then it will return the number.
Then on the bottom of the script we just give the numbers to the buses :-)
--[[
Goal: Give all buses a unique number
]]
-- Variables
local takenNumbers = {};
-- This function returns a random number in the range [100, 199] that has not been taken yet
function generateUniqueNumber()
local foundNumber = false;
while not foundNumber do
randomNumber = math.random(100, 199);
if not table.find(takenNumbers, randomNumber) then
table.insert(takenNumbers, randomNumber);
return randomNumber;
end
end
end
-- This function sets the number of the bus
script.Parent.pered.SurfaceGui.TextLabel.Text = tostring(generateUniqueNumber());
script.Parent.zad.SurfaceGui.TextLabel.Text = tostring(generateUniqueNumber());
script.Parent.levo.SurfaceGui.TextLabel.Text = tostring(generateUniqueNumber());
script.Parent.pravo.SurfaceGui.TextLabel.Text = tostring(generateUniqueNumber());
2 things:
I didn't test this code as Roblox is not installed on the pc I'm currently on.
Please try formatting your code nicely next time. It greatly improves the readability! For example, you can use this website:
https://codebeautify.org/lua-beautifier
Simpler
Fill a table with free numbers...
local freenumbers = {}
for i = 1, 99 do freenumbers[i] = i + 100 end
...for every new takennumbers use table.remove() on freenumbers
local takennumbers = {}
if #freenumbers > 0 then
takennumbers[#takennumbers + 1] = table.remove(freenumbers, math.random(1, #freenumbers))
end

save strings in lua table

Does someone know a solution to save the key and the values to an table? My idea does not work because the length of the table is 0 and it should be 3.
local newstr = "3 = Hello, 67 = Hi, 2 = Bye"
a = {}
for k,v in newstr:gmatch "(%d+)%s*=%s*(%a+)" do
--print(k,v)
a[k] = v
end
print(#a)
The output is correct.
run for k,v in pairs(a) do print(k,v) end to check the contents of your table.
The problem is the length operator which by default cannot be used to get the number of elements of any table but a sequence.
Please refer to the Lua manual: https://www.lua.org/manual/5.4/manual.html#3.4.7
When t is a sequence, #t returns its only border, which corresponds to
the intuitive notion of the length of the sequence. When t is not a
sequence, #t can return any of its borders. (The exact one depends on
details of the internal representation of the table, which in turn can
depend on how the table was populated and the memory addresses of its
non-numeric keys.)
Only use the length operator if you know t is a sequence. That's a Lua table with integer indexes 1,..n without any gap.
You don't have a sequence as you're using non-numeric keys only. That's why #a is 0
The only safe way to get the number of elements of any table is to count them.
local count = 0
for i,v in pairs(a) do
count = count + 1
end
You can put #Piglet' code in the metatable of a as method __len that is used for table key counting with length operator #.
local newstr = "3 = Hello, 67 = Hi, 2 = Bye"
local a = setmetatable({},{__len = function(tab)
local count = 0
for i, v in pairs(tab) do
count = count + 1
end
return count
end})
for k,v in newstr:gmatch "(%d+)%s*=%s*(%a+)" do
--print(k,v)
a[k] = v
end
print(#a) -- puts out: 3
The output of #a with method __len even is correct if the table holds only a sequence.
You can check this online in the Lua Sandbox...
...with copy and paste.
Like i do.

Generating all combinations from a table in Lua

I'm trying to iterate through a table with a variable amount of elements and get all possible combinations, only using every element one time. I've landed on the solution below.
arr = {"a","b","c","d","e","f"}
function tablelen(table)
local count = 0
for _ in pairs(table) do
count = count + 1
end
return count
end
function spellsub(table,start,offset)
local str = table[start]
for i = start+offset, (tablelen(table)+1)-(start+offset) do
str = str..","..table[i+1]
end
return str
end
print(spellsub(arr,1,2)) -- Outputs: "a,d,e" correctly
print(spellsub(arr,2,2)) -- Outputs: "b" supposed to be "b,e,f"
I'm still missing some further functions, but I'm getting stuck with my current code. What is it that I'm missing? It prints correctly the first time but not the second?
A solution with a coroutine iterator called recursively:
local wrap, yield = coroutine.wrap, coroutine.yield
-- This function clones the array t and appends the item new to it.
local function append (t, new)
local clone = {}
for _, item in ipairs (t) do
clone [#clone + 1] = item
end
clone [#clone + 1] = new
return clone
end
--[[
Yields combinations of non-repeating items of tbl.
tbl is the source of items,
sub is a combination of items that all yielded combination ought to contain,
min it the minimum key of items that can be added to yielded combinations.
--]]
local function unique_combinations (tbl, sub, min)
sub = sub or {}
min = min or 1
return wrap (function ()
if #sub > 0 then
yield (sub) -- yield short combination.
end
if #sub < #tbl then
for i = min, #tbl do -- iterate over longer combinations.
for combo in unique_combinations (tbl, append (sub, tbl [i]), i + 1) do
yield (combo)
end
end
end
end)
end
for combo in unique_combinations {'a', 'b', 'c', 'd', 'e', 'f'} do
print (table.concat (combo, ', '))
end
For a tables with consecutive integer keys starting at 1 like yours you can simply use the length operator #. Your tablelen function is superfluous.
Using table as a local variable name shadows Lua's table library. I suggest you use tbl or some other name that does not prevent you from using table's methods.
The issue with your code can be solved by printing some values for debugging:
local arr = {"a","b","c","d","e","f"}
function spellsub(tbl,start,offset)
local str = tbl[start]
print("first str:", str)
print(string.format("loop from %d to %d", start+offset, #tbl+1-(start+offset)))
for i = start+offset, (#tbl+1)-(start+offset) do
print(string.format("tbl[%d]: %s", i+1, tbl[i+1]))
str = str..","..tbl[i+1]
end
return str
end
print(spellsub(arr,1,2)) -- Outputs: "a,d,e" correctly
print(spellsub(arr,2,2)) -- Outputs: "b" supposed to be "b,e,f"
prints:
first str: a
loop from 3 to 4
tbl[4]: d
tbl[5]: e
a,d,e
first str: b
loop from 4 to 3
b
As you see your second loop does not ran as the start value is already greater than the limit value. Hence you only print the first value b
I don't understand how your code is related to what you want to achieve so I'll leave it up to you to fix it.

Check for identical elements in a table in Lua?

How would you check a table for three identical elements (looking for three L's)?
table = {nil, nil, L, nil, L} -> false
table = {L, L, nil, nil, L} -> true
Really would appreciate some help!
EDIT: Ok I've got this, but it only outputs false even when there are three or more L's (and does so five times for every check?). Sorry if it seemed like I was trying to get the code for it, I'm genuinely trying to learn! :)
for k, v in pairs( threeL_table ) do
local count = 0
if k == 'L' then
count = count + 1
end
if count == 3 then
print('true')
else
print('false')
end
end
You were almost there. You need to test the values v against 'L', not the keys k. Also, I suppose you want to print the message only once after the scan is concluded; if so, put the if-statement outside of the for-loop. (In this case, you should define count outside of the for-loop, too, otherwise you would not see it once it has ended).
local count = 0
for k, v in pairs( threeL_table ) do
if v == 'L' then -- you need to check for the values not the keys
count = count + 1
end
end
if count == 3 then -- move this out of the for-loop
print('true')
else
print('false')
end
I will not give you any code as you did not show any own efforts to solve the problem.
How would you check a table for three identical elements? Well you count them.
Loop over the table and for every distinct value you create a new counter. You could use another table for that. Once one of those counters reaches 3 you know that you have three identical values.
Another way to solve this.
function detectDup(t,nDup)
table.sort(t)
local tabCount = {}
for _,e in ipairs(t) do
tabCount[e] = (tabCount[e] or 0) + 1
if tabCount[e] >= 3 then
print("The element '" .. e .. "' has more than 3 repetitions!")
return true
end
end
return false
end
print(detectDup({'L', 'L','A','B'},3))
print(detectDup({'L', 'L','A','B','L',},3))

Lua Array shuffle not working

I was working on a script to randomize the data inside of my array but I get and error
that says
unexpected symbol near "#"
When I go to that line, and I remove the "#" I get
attempt to perform arithmetic on local `n' (a table value)
Here is my shuffle function
function shuffle(array)
local array = array
local n = #array
local j
local random = math.random
for i=n-1, 1, -1 do
j = random(i)
array[j],array[i] = array[i],array[j]
end
return array
end
and here is what I am trying to randomize
shuffle(new_players)
for name,character in pairs(new_players) do
if (character.inside == true and character.death == 0) then
local player = getPlayerByName(name, map_copy)
if (player ~= nil) then
addState(player)
break
end
end
end
Here is my array
new_players= { }
new_players[charName] = { death = 0, inside= true }
Any help? If i am doing something completely wrong?
1) Try change charName from string to a number.
2) For shuffle you can use this code:
function swap(array, index1, index2)
array[index1], array[index2] = array[index2], array[index1]
end
function shuffle(array)
local counter = #array
while counter > 1 do
local index = math.random(counter)
swap(array, index, counter)
counter = counter - 1
end
end
If your Lua version is < 5.1 then there is no # operator. Use table.getn instead:
local n = table.getn(array);
(Update) Note that your function, while it does shuffle the items around, it does not really shuffle all elements. Also since you reduce the range with each iteration, you will almost certainly swap the first 10% of your array around multiple times. Now swapping them multiple times is not bad by itself, but that you are, by comparison, almost never swapping the other elements is.
So one option to solve this would be to always use the same range for your random variable. And I would go even further and select two random indexes to swap:
function shuffle(array)
local n, random, j = table.getn(array), math.random
for i=1, n do
j,k = random(n), random(n)
array[j],array[k] = array[k],array[j]
end
return array
end
The other option would be to select random elements from the source array and put them into a new output array:
local rnd,trem,getn,ins = math.random,table.remove,table.getn,table.insert;
function shuffle(a)
local r = {};
while getn(a) > 0 do
ins(r, trem(a, rnd(getn(a))));
end
return r;
end

Resources