I am trying to translate the below javascript "bestSum" memoization function into lua:
const bestSum = (targetSum,numbers,memo ={}) => {
if(targetSum in memo) return memo[targetSum];
if(targetSum === 0 ) return [];
if(targetSum <0)return null;
let shortestCombination = null;
for (let num of numbers) {
const remainder = targetSum - num;
const remainderCombination = bestSum(remainder,numbers,memo);
if (remainderCombination !==null) {
const combination = [...remainderCombination, num];
if (shortestCombination === null || combination.length < shortestCombination.length)
{
shortestCombination = combination;
}
}
}
memo [targetSum] = shortestCombination;
return shortestCombination;
}
sample test cases with correct results:
console.log(bestSum(7,[5,3,4,7])); //[7]
console.log(bestSum(8,[2,3,5])); //[3,5]
console.log(bestSum(8,[1,4,5])); //[4,4]
console.log(bestSum(100,[1,2,5,25])); //[25,25,25,25]
I translated the above javascript into lua as the following:
local function BestSum(target_sum,numbers,memo)
if memo[target_sum] ~= nil then return memo[target_sum] end
if target_sum == 0 then return {} end
if target_sum < 0 then return nil end
local shortest_combination = nil
for i, num in ipairs (numbers) do
local remainder = target_sum - num
local remainder_combination = BestSum(remainder,numbers, memo)
if remainder_combination ~= nil then
local combination = remainder_combination
table.insert(combination,num )
if (shortest_combination == nil) or (#combination < #shortest_combination )then
shortest_combination = combination
end
end
end
memo[target_sum] = shortest_combination;
return shortest_combination;
end
but don't get the desired results for the two last cases...... instead get incorrect results:
BestSum(8,{1,4,5},{})==>{"4","1","4"}
BestSum(150,{5,25},{})==>
{"25","5","5","5","5","5","25","5","25","5","25","5","25","5","25","5","25","5","25","5","25","5","25","5","25","5","25","5","25","5","25","5","25","5","25","5","25","5","25","5","25","5","25","5","25","5","25"}
The results are not even correct let alone being "best" case??
Can anyone spot where I'm going wrong?
Much appreciated
The problem is with this part of the translation:
local combination = remainder_combination
table.insert(combination, num)
Tables are pass by reference, so this isn't creating a new table, it's just assigning the variable combination to the same table. Modifying combination is just adding more data to remainder_combination.
The JavaScript version is taking care to create a new array, and fills it with the contents of the remainderCombination array (using '...', the spread operator):
const combination = [...remainderCombination, num];
This is the most accurate Lua translation:
local combination = {unpack(remainder_combination)}
table.insert(combination, num)
(Edit: For Lua 5.2+ it's table.unpack)
Related
I'm looking for a way to retrive index value via metatable. This is my attempt:
local mt = { __index =
{
index = function(t, value)
local value = 0
for k, entry in ipairs(t) do
if (entry == value) then
value = k
end
end
return value
end
}
}
t = {
"foo", "bar"
}
setmetatable(t,mt)
print(t.index(t,"foo"))
Result is 0 instead of 1. Where I'm wrong?
My attempt:
local mt = {
__index = function(t,value)
for index, val in pairs(t) do
if value == val then
return index
end
end
end
}
t = {
"foo",
"bar",
"aaa",
"bbb",
"aaa"
}
setmetatable(t,mt)
print(t["aaa"]) -- 3
print(t["asd"]) -- nil
print(t["bbb"]) -- 4
print(t["aaa"]) -- 3
print(t["bar"]) -- 2
print(t["foo"]) -- 1
Result is 0 instead of 1. Where [am I] wrong?
The code for the index function is wrong; the problem is not related to the (correct) metatable usage. You're shadowing the parameter value when you declare local value = 0. Subsequent entry == value comparisons yield false as the strings don't equal 0. Rename either the parameter or the local variable:
index = function(t, value)
local res = 0
for k, entry in ipairs(t) do
if entry == value then
res = k
end
end
return res
end
An early return instead of using a local variable in the first place works as well and helps improve performance.
To prevent such errors from happening again, consider getting a linter like Luacheck, which will warn you if you shadow variables. Some editors support Luacheck out of the box; otherwise there are usually decent plugins available.
I found this Gist for money formatting on Shopify using JavaScript https://gist.github.com/stewartknapman/8d8733ea58d2314c373e94114472d44c
I placed it in my cart page and when I try:
Shopify.formatMoney(2000, '$')
I get this:
cart:2166 Uncaught TypeError: Cannot read property '1' of null
at Object.Shopify.formatMoney (cart:2166)
at <anonymous>:1:9
this is at switch(formatString.match(placeholderRegex)[1]) {
I expect to get $20.00
Do you know where the problem is?
Similar question: Shopify Buy Button Error: "cannot read property '1' of null"
The Gist content
var Shopify = Shopify || {};
// ---------------------------------------------------------------------------
// Money format handler
// ---------------------------------------------------------------------------
Shopify.money_format = "${{amount}}";
Shopify.formatMoney = function(cents, format) {
if (typeof cents == 'string') { cents = cents.replace('.',''); }
var value = '';
var placeholderRegex = /\{\{\s*(\w+)\s*\}\}/;
var formatString = (format || this.money_format);
function defaultOption(opt, def) {
return (typeof opt == 'undefined' ? def : opt);
}
function formatWithDelimiters(number, precision, thousands, decimal) {
precision = defaultOption(precision, 2);
thousands = defaultOption(thousands, ',');
decimal = defaultOption(decimal, '.');
if (isNaN(number) || number == null) { return 0; }
number = (number/100.0).toFixed(precision);
var parts = number.split('.'),
dollars = parts[0].replace(/(\d)(?=(\d\d\d)+(?!\d))/g, '$1' + thousands),
cents = parts[1] ? (decimal + parts[1]) : '';
return dollars + cents;
}
switch(formatString.match(placeholderRegex)[1]) {
case 'amount':
value = formatWithDelimiters(cents, 2);
break;
case 'amount_no_decimals':
value = formatWithDelimiters(cents, 0);
break;
case 'amount_with_comma_separator':
value = formatWithDelimiters(cents, 2, '.', ',');
break;
case 'amount_no_decimals_with_comma_separator':
value = formatWithDelimiters(cents, 0, '.', ',');
break;
}
return formatString.replace(placeholderRegex, value);
};
I found formatMoney function in my theme and I was able to call it and it worked.
pipelineVendor.themeCurrency.formatMoney(2000);
result: $20.00
It's probably too late for the original asker, but for anyone else looking for an answer, I believe the correct call for this function is:
Shopify.formatMoney(2000, '${{amount}}')
instead of
Shopify.formatMoney(2000, '$')
based on the comment of the gist author on Github:
It doesn’t actually care what the currency is. The first argument is
the unformatted amount. The second argument is the format, which could
be whatever you need for the currently displayed currency i.e. “£{{
amount }}”. Then pass it a new amount and new format when you change
the currency.
We are currently pulling in data from SalesForce to SQL Database tables. There are 2 custom fields on different objects that were created for the Lead ID and a look up for which event/task is linked (this can be an account id, contact id, or lead id). Both of these are pulling over the 15 digit ID.
I am trying to find out if there is any SQL code or a SQL function that will allow me to convert that 15 digit to an 18 digit ID.
I need to have that 18 digit ID to join back to the other objects.
We have already tried using the CASESAFEID(Id) function in SalesForce, but with the API that was already set up and the visibility levels our particular ETL is not showing that field. Also, we would need to get a consultant to mess with the look up column.
I would like to take the 15 digit ID and convert it to the 18 digit code. If the SalesforceID is 0035000002tAzbu, how do I get the converted 18 digit value to be 0035000002tAzbuACC. I need to get that last 3 digits using SQL query or SQL function.
you could write a custom function in your sql database.
e.g. in snowflake, you can make a function like this
CREATE OR REPLACE FUNCTION dw.my_schema.f_sfdc_ch15_to_ch18("txt" string)
RETURNS string
LANGUAGE JAVASCRIPT
AS '
if ( txt == undefined || txt == "" || typeof txt == "undefined" || txt == null) {
return ;
} else {
var id15, id18;
if (txt.length == 18) {
return txt;
} else if (txt.length == 15) {
id15 = [txt.trim()];
} else {
return "";
}
for ( var x=0; x < id15.length; x++ ) {
var s = "";
for ( var i=0; i<3; i++) {
var f = 0;
for (var j=0; j<5; j++) {
var c = id15[x].charAt(i*5+j);
if (c>="A" && c<="Z") {
f+=1<<j;
}
}
s += "ABCDEFGHIJKLMNOPQRSTUVWXYZ012345".charAt(f);
}
id18 = id15[x]+s;
}
}
return id18.toString();
';
and use it like this
select dw.my_schema.f_sfdc_ch15_to_ch18(id15) from mytable;
This value can be computed. Check out this flowchart.
Source: https://stackoverflow.com/a/29299786/3135974
Im trying to get all the data rows that contain a certain set of data.
In my database i have some values, including start and length.
I have an array that contains integers called startTimes and another called endTimes.
I need a where clause that would return the records that have a start value contained in startTimes, OR start+length contained in endTimes.
Is there any way to do this?
Thanks
IQueryable<request> proposedRequest = db.requests.Include(r => r.rooms);
proposedRequest = proposedRequest.Where(r=>r.booked.Equals(1));
proposedRequest = proposedRequest.Where(r=>r.roundID.Equals(roundID))8;
proposedRequest = proposedRequest.Where(r=>r.day.Equals(day));
int[] startTimes;
int[] endTimes;
for(var q=0;q<time;q++){
startTimes[startTimes.Length] = time + q;
endTimes[endTimes.Length] = time + q + 1;
}
proposedRequest = proposedRequest.Where(//what goes in here);
i have an array startTime=[1,3,4] and an array endTime=[2,4,5] lets
say. I need to see if any of those values match my records? I dont
think the above would do the job
To check if you have value in Array of int, Use the Contains Method:
proposedRequest = proposedRequest.Where(s => startTimes.Contains(s.INT_ID)
|| endTimes.Contains(s.INT_ID));
Syntax: ARRAY.Contains(ID_TO_SEARCH)
it returns a boolean:
var list = new List<int> {1,2,3,4,5};
var intVar = 4;
var exists = list.Contains(intVar);
will something like this suffice?
var data = collection.Where(
t => startTimes.Contains(t.theTime) ||
endTimes.Contains(t.theTime + theLength));
proposedRequest.Where(pr => startTimesArray.Contains(pr.start) || endTimesArray.Contains(pr.start + pr.length));
I have problem; I must check in my program one field in table.
if(launchArgs.androidIntent.extras.notification.custom.test_field ~= nil)then...
and when this index exist everything is ok, but when it isn't exist, I get an error :
Attempt to index field 'notification' (a nil value).
And it is understandable. How check if that index exist?
Try this
if (launchArgs and launchArgs.androidIntent and launchArgs.androidIntent.extras
and launchArgs.androidIntent.extras.notification and launchArgs.androidIntent.extras.notification.custom
and launchArgs.androidIntent.extras.notification.custom.test_field) then
-- do you stuff
end
This code will check if each table is set.
If you're sure launch args.androidIntent.extras is always set you can just do this
if(launchArgs.androidIntent.extras.notification and launchArgs.androidIntent.extras.notification.custom and launchArgs.androidIntent.extras.notification.custom.test_field)then
-- do your stuff
end
OR Just use this function, that I posted in some other answer (helps here too )
function IndexScan(input,value,case,_type)
if (input and type(input) == 'table') then
if (_type) then
if (type(value) == _type and value == input) then
return true;
end
else
if (type(value) == 'table' and value == input) then
return true;
end
end
for key,object in pairs(input) do
if (case and type(input)=='string' and type(key)=='string') then
if (_type) then
if (value:lower() == key:lower() and type(object)==_type) then
return true;
elseif(type(object)=='table') then
return IndexScan(object,value,case,_type)
end
else
if (value:lower() == key:lower()) then
return true;
elseif(type(object)=='table') then
return IndexScan(object,value,case,_type)
end
end
else
if (_type) then
if (key == value and type(object)==_type) then
return true
elseif(type(object)=='table') then
return IndexScan(object,value,case,_type)
end
else
if (key == value) then
return true
elseif(type(object)=='table') then
return IndexScan(object,value,case,_type)
end
end
end
end
end
return false;
end
-- IndexScan(#param table(table), #param index(string), #param case-sensitive(true/false), #param type (index type, string/boolean/number/table ...))
-- checks if these two indexes were set any where in the launchArgs table and checks their type
if (IndexScan(launchArgs,"notification",false,"table") and IndexScan(launchArgs,"test_field",false,"string")) then
-- do your stuff
end
EDIT:
Fixed some mistake in the function.
EDIT:
Updated the script after the author fixed the Notification typo.
Try also this:
function setglobal(name,value)
local t=_ENV
local f="_G"
for x in name:gmatch("[^.]+") do
if t[f]==nil then t[f]={} end
t=t[f]
f=x
end
t[f]=value
end
function getglobal(name)
local t=_ENV
for x in name:gmatch("[^.]+") do
t=t[x]
if t==nil then return nil,x end
end
return t
end
setglobal("launchArgs.androidIntent.extras.notification.custom.test_field",2014)
print(getglobal("launchArgs.androidIntent.extras.notification.custom.test_field"))
print(getglobal("launchArgs.androidIntent.extras.notifiaction.custom.test_field"))
This assumes that the top-level variable is a global variable. Adapt as needed.
You can use this:
local function try(root, query)
local ids, len = {}, 0
for id in query:gmatch("%w+") do
len = len + 1
ids[len]= id
end
local node = root
for i=1,len do
if type(node) ~= 'table' then return nil end
node = node[ids[i]]
end
return node
end
Usage:
local tbl = { a = { b = { c = { d = 1 } } } }
print(try(tbl, 'a.b.c.d')) -- prints 1
print(try(tbl, 'a.b.c.x')) -- prints nil
print(try(tbl, 'a.x.c.d')) -- prints nil