Reputation: 3
I am developing an API which will take 2 objects and an expression and perform filtering of false statement. returns third object which will have only those dataset where the expression is evaluated true.
var obj1 = [
{cn: 101, name: "AA", seq:1},
{cn: 106, name: "BB", seq:2}
];
var obj2 = [
{ cid: 100, name: "XX", locator: "r" },
{ cid: 101, name: "AA", locator: "p"},
{ cid: 507, name: "TT", locator: "r"}
];
var output = MyClass.filter(obj1, obj2, "{source.cn}==={target.cid}");
obj1 is source object
obj2 is target object
expected output is:
output = [
{ cid: 101, name: "AA", locator: "p"}
];
since my class is a generic class it should be able to accept any two object(of any structure and depth) and perform any valid javascript expression. hence I find the path of given expression and prepare the list of expressions.
source[0]["cn"]===target[0]["cid"]
source[0]["cn"]===target[1]["cid"]
source[0]["cn"]===target[2]["cid"]
source[1]["cn"]===target[0]["cid"]
source[1]["cn"]===target[1]["cid"]
source[1]["cn"]===target[2]["cid"]
After getting the expressions I eval each of them and filter-out false ones.
eval(source[0]["cn"]===target[0]["cid"]) >>>>>EVAL RESULT>>>>> false
eval(source[0]["cn"]===target[1]["cid"]) >>>>>EVAL RESULT>>>>> true
eval(source[0]["cn"]===target[2]["cid"]) >>>>>EVAL RESULT>>>>> false
eval(source[1]["cn"]===target[0]["cid"]) >>>>>EVAL RESULT>>>>> false
eval(source[1]["cn"]===target[1]["cid"]) >>>>>EVAL RESULT>>>>> false
eval(source[1]["cn"]===target[2]["cid"]) >>>>>EVAL RESULT>>>>> false
When these 2 objects contain say obj1 100 possible paths and obj2 1000 possible paths, myclass produces 100,000 statements to eval. thats it, it runs for ever well known eval is slow but since these statements are string I am unable to put it in "if"
I tried a test code where i used statements in if statements, it was very - very fast. i want to use if over eval.
My test code is given below:
var before = Date.now();
var str, result, results = [], m, n;
for(var i = 0, j=0; i <100000, j<100000; ++i,++j ){
str = i + "===" + j;
//eval(str)
if(i === j) {
result = true;
} else {
result = false;
}
}
var after = Date.now();
console.log("Time: ", (after - before));
Since these expressions can be any valid JS expression I can not assume operators. users are free to used any kind of operators(Assignment, Comparison, Arithmetic, Bitwise, Logical, String or Special operators) in expression.
for example :
"{source.cn}==={target.cid} && {target.name} != 'XX'"
or
"({source.cn}==={target.cid} || {source.cn}/100 === 1 )&& {target.name} != 'XX'"
or anything else.
I dont want to write my own expression parser.
Please help by providing (without using eval) 1. alternative approach (but not (new Function(expr)()) 2. some way to use "if" over "eval" will make my code very fast. like the above test proves. 3. Any other approach to make it fast without compromising on requirement. (and yes there could be multiple matches in target object)
Thanks in advance.
Upvotes: 0
Views: 384
Reputation: 17579
There is likely no need for eval in the first place.
Just switch from passing in a string
var output = MyClass.filter(obj1, obj2, "{source.cn}==={target.cid}");
to use a function
function comparator(source, target) {
return source.cn===target.cid
}
var output = MyClass.filter(obj1, obj2, comparator);
and your filter would be much simple!
function filter(array1,array2, comparator) {
var ret = []
array1.forEach(function(source) {
array2.forEach(function(target) {
if (comparator(source,target)) ret.push(source)
}
})
return ret
}
Of course if performance is a concern you are going to replace Array.forEach
with simple for
.
Upvotes: 3