Lodash memoize key when the function being memoized accepts functions? - javascript

I have a large data collection that I frequently query by first applying a filter to it. I want to cache and reuse the results of the different filter functions I use because this part can be expensive. Here's a rough simulation of this:
const a = x => x + 1;
const b = x => x + 2;
const m = _.memoize(
f => (console.log('filtering data'), f(314159)),
f => String(f)
);
console.log(m(a));
console.log(m(b));
console.log(m(a));
console.log(m(b));
Here "a" and "b" would be the filter functions I want to use and "m" is acting on the same data each time.
How do I specify the key for the _.memoize function?
The above works but I'm using the string representation of the function which feels wrong. Is there a better way?
I'm worried this isn't safe when minification is applied. In my actual code, the "memoize" part is in one ES6 module, the "a" and "b" parts are in another module and the calls to "m" are in several different modules which import the "a" and "b" function. Will the string representation be stable across modules like this? Is converting to the string representation fast?
The only alternative I can think of is to create a string -> function dictionary so you would do calls like m("a") but JavaScript linters won't pick up if the name is wrong.

The above works but I'm using the string representation of the function which feels wrong.
Indeed.
I'm worried this isn't safe when minification is applied.
No, minification is not the problem. Different functions get minified to different code.
The problem is closures:
const addTo = x => y => x + y
const a = addTo(1),
b = addTo(2);
console.log(String(a) === String(b));
You can only reliably compare functions by their object identity. The best way would probably be to update Lodash to use an ES6 WeakMap that doesn't require any stringification.
As long as such is not available, you can use
const id = Symbol("function identity");
let count = 0;
function toMemoizeKey(fn) {
return fn[id] || (fn[id] = ++count);
}

Related

Convert JS interpolation string to function call

I'm writing some code that rips string literals out of Typescript/JavaScript source as the first stage of a localisation toolchain I have planned.
The fly in the ointment is string interpolation.
I was on the verge of writing a function to transform an interpolation string into a function call that rips the expressions and then replaces the interpolation string with a function call that takes the expressions as parameters.
const a = 5;
const b = 7;
const foo = `first value is ${a + b}, second value is ${a * b}`;
becomes
import { interpolate } from "./my-support-code";
...
const a = 5;
const b = 7;
const foo = interpolate("first value is ${0}, second value is ${1}", [a + b, a * b]);
with the interpolate function working through the array values and replacing strings generated from the ordinal position
function interpolate(template: string, expressions: Array<any>): string {
for (let i = 0; i < expressions.length; i++) {
template = template.replace("${" + i + "}", expressions[i].toString());
}
return template;
}
This will probably work (not yet tried) but it occurred to me that this is probably a thoroughly invented wheel. The question is basically is there a well-established package that does a comprehensive job of this?
I know the above doesn't localise anything. The point is to be rid of interpolation strings so the substitution mechanism can assume that all strings are simple literals. The base language string taken from the above would be "first value is ${0}, second value is ${1}" and translators would be expected to place the tokens appropriately in whatever string they produce.
If you're going to tackle this on a non-trivial sized code base, the best you can really do is:
Write a regular expression to identify common types of localization targets and identify them, probably by file + line number.
Add comments to your code in these locations using a keyword that's easy to git grep for, or even something that can be added to your editor's syntax highlighting rules. Personally I use things like // LOCALIZE.
If you're feeling ambitious, you could implement a rewriter that attempts to convert from template form to your localization's template requirements. Each conversion can be individually inspected, altered as required, and introduced. Hopefully you have test coverage to verify your code still works after this.

Can I be sure that this will always returning a unique alphanumeric string?

I'm trying to generic a universally unique alphanumeric string in javascript. I've tried to use UUID but the format isn't desirable. Currently I am doing the following:
Math.floor((Math.random() * Date.now())).toString(16).toUpperCase()
This results in a string like: 4198A8BEA4. This is the desired format and relative length.
Can I be sure that this will always return a unique alphanumeric string?
If so, how can I be sure?
Nope, the resulting string will probably have 10 or 11 characters, and the characters will vary from 1 to F, so there are 16 ** 10 = 1099511627776 possibilities.
The likelihood of a collision is low - it'll probably be good enough for most code - but it's not zero.
To guarantee no collisions, the easiest way would be to use numeric indicies instead, and increment each time a new one is needed.
let i = 0;
const getNextUnique = () => i++;
console.log(getNextUnique());
console.log(getNextUnique());
The index is easy to see in the result, though. If that's a problem for you, use a one-way hash function without collisions on it. (though, even cryptographic hash functions can have collisions, depending on the algorithm)
SHA-256 does not have any known collisions, and such a collision is considered near impossible under current circumstances, so you could use it if you wanted:
let i = 0;
const getNextUnique = async () =>
Array.prototype.map
.call(
new Uint8Array(
await crypto.subtle.digest("SHA-256", new TextEncoder().encode(i++))
),
(x) => ("0" + x.toString(16)).slice(-2)
)
.join("");
(async () => {
console.log(await getNextUnique());
console.log(await getNextUnique());
})();

Is there a way to mutate strings without using all kinds of different methods?

I have a project in which i need to split an ID into two separate IDs.
The first Id has a static length of 20 chars and the second is variable.
I currently have the following code in place:
mergedUUID = "12345678902345678900123";
const serverUUIDlength = 20;
const cameraId = mergedUUID.slice(serverUUIDlength);
const deviceId = mergedUUID.substring(serverUUIDlength);
Resulting in deviceId being 12345678902345678900 and cameraId 123.
But this feels "dumb", I use these two different methods while they are doing practically the same, it there a better (more clean) way?
You are confusing two different methods. While they are really alike there are subtle difference between them.
substring has something of a foolproof method to 'always' work. For example it swaps it's parameters around if the given startIndex is greater than the endIndex. Slice in this case would have returned an empty string.
Example code:
var text = 'Mozilla';
console.log(text.substring(5, 2)); // => "zil"
console.log(text.slice(5, 2)); // => ""
To answer your question; you should consider using one method, not both. That's the better way.
For additional documentation, click here.
You could slice, the one from start, the other one from a given position.
var mergedUUID = "12345678902345678900123",
serverUUIDlength = 20,
deviceId = mergedUUID.slice(0, serverUUIDlength),
cameraId = mergedUUID.substring(serverUUIDlength);
console.log(deviceId);
console.log(cameraId);

F# compose functions

i am trying to learn F# functional programming but i have some issues translating some concepts from Javascript functional programming to F#. I have this code that enables me to compose a "pipeline" of functions in Javascript like this:
const compose = ((functions) => {
return ((input) => {
return functions.reduce((ack, func) => {
return func(ack);
}, input);
});
});
const addOne = ((input) => input + 1);
const addTwo = ((input) => input + 2);
const composedFunction = compose([addOne, addTwo]);
const result = composedFunction(2);
console.log(result);
Is it even possible to do this kind of composition in F#? How would i do it?
Assuming that the list of functions you need to compose is not known at compile time, you can use a fold to compose your list of functions.
In your answer I see you found a very close solution with reduce which is a special case of fold but it doesn't have an initial state so when the list is empty it fails.
Since we can't have compile guarantee that the list is not empty I highly recommend you for this scenario using a fold, having the id function as initial state:
let compose funcs = (fun x -> x |> List.fold (>>) id funcs)
We can apply eta reduction:
let compose funcs = List.fold (>>) id funcs
One more time:
let compose = List.fold (>>) id
Although with this last step you will run in the value restriction, but it might disappear with the rest of the code:
let addOne x = x + 1
let addTwo x = x + 2
let compose = List.fold (>>) id
let list = [addOne; addTwo]
let composed = compose list
let elist = []
let composed2 = compose elist
// test
let result = composed 1
let result2 = composed2 1
// val result : int = 4
// val result2 : int = 1
This code got me the solution that i wanted:
let addOne x = x + 1
let addTwo x = x + 2
let compose funcs =
(fun x -> x |> List.reduce (>>) funcs)
let list = [addOne; addTwo]
let composed = compose list
let result = composed 1
If you're composing a number of functions that is fixed at compile time you should use >> directly:
let addOne n = n + 1
let addTwo n = n + 2
let addThree = addOne >> addTwo
You say that you're just learning F#, so I'll risk stating the obvious here - this is how you compose functions in F#:
addOne >> addTwo
Functional programming in a statically-typed FP-first language like F# has a very different flavor than encoding the same approach in a language that is not geared to it (like JS or C#). Things that in those languages have to be encoded with dedicated functions, like partial application or function composition, are directly exposed in the language itself.
For instance, while you can express the same pattern of sequentially applying a collection of functions to a value in F#, you will find it both an overkill (because it can be replaced by a simple function composition) and less powerful compared to JS equivalent (because you can't compose functions with different types this way, e.g. you can't compose an int -> string and a string -> bool because list requires all elements to be the same type, something that JS doesn't care at all about).
In JS this pattern might be "the way" to do function composition - you need a function for it anyway, it might as well take a collection of them while you're at it, but translating it directly into F# is less useful than it seems. Case in point - I have maybe used it once or twice over many years of writing F#, and I can't say it was unavoidable. If you find yourself wanting to use this pattern over and over in F#, you might need to revisit how you're doing things.

Use window to execute a formula instead of using eval

My code need to execute a forumla (like Math.pow(1.05, mainObj.smallObj.count)).
My path is :
var path = mainObj.smallObj.count;
as you can see.
If needed, my code can split all variable names from this path and put it in an array to have something like :
var path = ["mainObj", "smallObj", "count"];
Since I don't want to use eval (this will cause memory leaks as it will be called many times every seconds), how can I access it from window?
Tried things like window["path"] or window.path.
If it is always unclear, let me know.
Thanks in advance for any help.
EDIT: forget to tell that some config are written in JSON, so when we take the formula, it's interpreted as "Math.pow(1.05, mainObj.smallObj.count)" so as a string.
I would say there are better solutions then eval, but it depends how the forumla can be structured. It could be precompiled using new Function (this is also some kind of eval) but allowing it to be called multiple times without the need to recompile for each invocation. If it is done right it should perform better then an eval.
You could do something like that:
var formula = {
code : 'Math.pow(1.05, mainObj.smallObj.count)',
params : ['mainObj']
}
var params = formula.params.slice(0);
params.push('return '+formula.code);
var compiledFormula = Function.apply(window, params);
//now the formula can be called multiple times
var result = compiledFormula({
smallObj: {
count: 2
}
});
You can get the path part reconciled by recursively using the bracket notation:
window.mainObj = { smallObj: { count: 2 } };
var path = ["mainObj", "smallObj", "count"];
var parse = function (obj, parts) {
var part = parts.splice(0, 1);
if (part.length === 0) return obj;
obj = obj[part[0]];
return parse(obj, parts);
};
var value = parse(window, path);
alert(value);
Basically, parse just pulls the first element off the array, uses the bracket notation to get that object, then runs it again with the newly shortened array. Once it's done, it just returns whatever the result of the last run is.
That answers the bulk of your question regarding paths. If you're trying to interpret the rest of the string, #t.niese's answer is as good as any other. The real problem is that you're trusting code from an external source to run in the context of your app, which can be a security risk.

Categories

Resources