redis script check if hash field exists - lua

The question is about lua script in redis.
I'm trying to check if some field exists in a hash table, but the return value of redis.call suprised me:
EVAL 'local label = "oooo"; local tesid = redis.call("HGET", "nosuchkey", "nosuchfield"); if tesid == nil then label="aaaa" elseif tesid == "" then label="bbbb" else label = "kkkk" end; return {tesid,label}' 0
the return value is
1) (nil)
2) "kkkk"
I don't understand why I got into that else branch -- where label is set to "kkkk" -- when tesid is nil, I think it should output "aaaa".
Why does the script go into "kkkk" label?
For better reading, I paste the script here:
local label = "oooo"
local tesid = redis.call("HGET", "nosuchkey", "nosuchfield")
if tesid == nil
then
label="aaaa"
elseif tesid == ""
then
label="bbbb"
else
label = "kkkk"
end
return {tesid,label}

Short Answer: tesid is false NOT nil.
Redis' conversion rules for nil reply is as follows:
Redis nil reply is converted to Lua false boolean type.
Lua false boolean type is converted to Redis' nil reply.
In your case, HGET returns nil, which is converted to false. So tesid is false. It's not equal to either nil or "", so label is set to kkk. When your code returns tesid as part of the return value, it's converted to Redis' nil reply. And that's why you got {nil, kkk}

Related

Roblox Error: attempt to index local 'screengui' (a nil value)

Workspace.Part.Script:16: attempt to index local 'screengui' (a nil value)
wait(2) -- Testing to make sure assets loaded
script.Parent.Touched:connect(function(hit)
if not hit or not hit.Parent then return end
local human = hit.Parent:findFirstChild("Humanoid")
if human and human:IsA("Humanoid") then
local person = game.Players:GetPlayerFromCharacter(human.parent)
if not person then return end
person.Checklist.FirstEggCollected.Value = true
local playgui = person:FindFirstChild('PlayerGui')
print(playgui)
wait(0.2)
local screengui = playgui:FindFirstChild('ScreenGui')
wait(0.2)
print(screengui) -- This prints nil
local collectnotice = screengui:FindFirstChild('CollectionNotice') -- This is line 16
local Toggle = collectnotice.Toggle
local text = Toggle.Text
local value = text.Value
value = "The Easy Egg!"
person:WaitForChild('PlayerGui'):FindFirstChild('ScreenGui'):FindFirstChild('CollectionNotice').Toggle.Color.Value = Color3.fromRGB(0,255,0)
person:WaitForChild('PlayerGui'):FindFirstChild('ScreenGui'):FindFirstChild('CollectionNotice').Toggle.Value = true
script.Parent:Destroy()
wait(5)
game.Workspace.Variables.IfFirstEggInGame.Value = false
end
end)
I've been at this for hours. No idea how to make the error fix. FE is on, Yes its name is "ScreenGui" and it is inside "PlayerGui"
Error: Workspace.Part.Script:16: attempt to index local 'screengui' (a nil value)
From the Roblox manual: http://wiki.roblox.com/index.php?title=API:Class/Instance/FindFirstChild
Description: Returns the first child found with the given name, or nil
if no such child exists.
So there seems to be no child named "ScreenGui".
If a function may return nil you have to handle that properly. Blindly indexing possible nil values is bad practice.
Your issue is at the line local collectnotice = screengui:FindFirstChild('CollectionNotice').
You do not have an instance listed for the screengui variable.

Boolean to number in Lua

Is there a way to get 1 with true and 0 with false in Lua?
There is the tobool which gives true or false with 1 or 0, but tonumber gives a nil value with true or false.
You can combine and and or clauses like ternary operators.
function bool_to_number(value)
return value and 1 or 0
end
You can also do this:
bool_to_number={ [true]=1, [false]=0 }
print(bool_to_number[value])
Or this:
debug.setmetatable(true, {__len = function (value) return value and 1 or 0 end})
print(#true)
print(#false)
The answer from hjpotter92 takes any value different to nil as a true value (returning 1). This instead takes the value true or false.
local value = true
print(value == true and 1 or value == false and 0)
-- we add the false check because it would drop 0 in case it was nil
If you want to use a function instead, this would be it
local value = true
local function bool_to_number(value)
return value == true and 1 or value == false and 0
end
print(bool_to_number(value))

Lua not not the same as not not

I was using some coroutines and was trying to resume one using not:
if not co == nil then `resume end
and the coroutine wouldn't resume. Though co was nil. It was baffling.
So I eventually tried
if co then `resume end
and it worked!
why isn't not (nil == nil), which is logically false when co is nil and true when it is not which is not the same as as nil which is logically false when co is nil and true otherwise?
I use not all the time to negate the logical expression but now I'm worried that maybe some of my code is buggy. Maybe this only has a problem with coroutines? (and I'm 100% sure that the value is nil, because that is what is printed out, unless nil no longer equals nil)
not co == nil is equivalent to (not co) == nil because of operator precedence.
If co is nil, then not co is true and so different from nil.
In fact, the result of not is always true or false, and so never equal to nil.
Write not (co == nil) or co ~= nil.

How do I create a function that returns the first non-nil, non-empty string passed to it?

I'm trying to implement a function that returns the first non-blank string from the variables passed to it. Unfortunately, some of these variables might be nil, so the naive approach
function first_non_empty(...)
for i, item in ipairs({...}) do
if item ~= nil and item ~= '' then
return item
end
end
return ''
end
doesn't work: ipairs quits out as soon as it encounters a nil value. This can be fixed by changing the requirements so that the variables can't be nil, or by passing the length to the function so table length doesn't have to rely on ipairs, or by wrapping all parameters in a function so that none of them are explicitly nil
function first_non_empty_func(...)
for i, func in ipairs({...}) do
local item = func()
if item ~= nil and item ~= '' then
return item
end
end
return ''
end
function fn(p)
local f = function() return p end
return f
end
-- change callers to first_non_empty_func(fn(a), fn(b), fn(c))
However, both of these solutions complicate the function prototype. Does there exist a function taking an ordered list of parameters, some of which may be nil, which returns the first of those parameters which is both non-nil and not an empty string?
Use table.pack, which preserves all nil entries and returns the number of entries in the n field:
function first_non_empty_pack(...)
local t = table.pack(...)
for i = 1, t.n do
local item = t[i]
if item ~= nil and item ~= '' then
return item
end
end
return ''
end
select('#', ...) can be used to get the number of provided arguments, so here is an alternative that doesn't use table.pack:
function first_non_empty_pack(...)
for i = 1, select('#', ...) do
local item = select(i, ...)
if item ~= nil and item ~= '' then
return item
end
end
return ''
end
Simpler approach is to use recursion. No extra tables created, etc:
function first_non_empty(item, ...)
if item ~= nil and item ~= '' then return item end
return first_non_empty(...)
end
But the list has to end with some ending marker. For example, boolean 'false', indicating there's no non-nil, nonempty strings.

lua - checking for duplicate data in a string

I have the following string data that I receive as input:
"route1,1234,1,no~,,route2,1234,1,no~,"
It represents two "records" of data... where each record has 4 fields.
I've built code to parse this string into it's individual columns / fields.
But the part that isn't working is when I test to see if I have any duplicates in field 2. Field 2 is the one that currently has "1234" as the value.
Here's the code:
function string:split(delimiter)
local result = { }
local from = 1
local delim_from, delim_to = string.find( self, delimiter, from )
while delim_from do
table.insert( result, string.sub( self, from , delim_from-1 ) )
from = delim_to + 1
delim_from, delim_to = string.find( self, delimiter, from )
end
table.insert( result, string.sub( self, from ) )
return result
end
local check_for_duplicate_entries = function(route_data)
local route
local route_detail = {}
local result =true
local errtxt
local duplicate = false
print("received :" ..route_data)
route = string.gsub(route_data, "~,,", "~")
route = route:sub(1,string.len(route)-2)
print("route :" ..route)
-- break up in to an array
route = string.split(route,"~")
for key, value in pairs(route) do
route_detail[key] = string.split(value,",")
end
local list_of_second_column_only = {}
for key,value in pairs(route_detail) do
local temp = value[2]
print(temp .. " - is the value I'm checking for")
if list_of_second_column_only[temp] == nil then
print("i dont think it exists")
list_of_second_column_only[key] = value[2]
print(list_of_second_column_only[key])
else
--found a duplicate.
return true
end
end
return false
end
print(check_for_duplicate_entries("route1,1234,1,no~,,route2,1234,1,no~,"))
I think where I'm going wrong is the test:
if list_of_second_column_only[temp] == nil then
I think I'm checking for key with the value temp instead of a value with the value that temp contains. But I don't know how to fix the syntax.
Also, I'm wondering if there's a more efficient way to do this.
The number of "records" i receive as input is dynamic / unknown, as is the value of the second column in each record.
Thanks.
EDIT 1
The post I was trying to use as a reference is: Search for an item in a Lua list
In the answer, they show how to test for a record in the table by value, instead of looping through the entire table...
if items["orange"] then
-- do something
end
I was playing around to try and do something similar...
This should be a bit more efficient with only one table creation and less regex matching.
The match does require that you're only interested in dups in the second field.
local function check_for_duplicate_entries(route_data)
assert(type(route_data)=="string")
local field_set = {}
for route in route_data:gmatch"([^~]*)~,?,?" do
local field = route:match",([^,]*)"
if field_set[field] then
return true
else
field_set[field] = true
end
end
return false
end
Try this. It's doing the check on the value of the second field.
I haven't looked at the efficiency.
if list_of_second_column_only[value[2]] == nil then
print("i dont think it exists")
list_of_second_column_only[value[2]] = true
print(list_of_second_column_only[value[2]])
else
--found a duplicate.
return true
end

Resources