最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Dynamic generated condition JS - Stack Overflow

programmeradmin3浏览0评论

I'm looking for the best way to make dynamic generated condition inside a loop.

A sample worth thousand words so here is my code :

var condition = "data.label == 'Test'";

for (var key in andArray) {
    condition += "&& " + andArray[key];
}

for (var key in orArray) {
    condition += "|| " + orArray[key];
}

var length = dataArray.length;
var result = [];
for (var i = 0; i < length; i++) {
    var data = dataArray[i];
    if (eval(condition)) {
        result.push(obj);
    }
}

I use the eval() function, which works well but that is REALLY too slow ! For a 200 elements array, this code take 25ms to be executed ! This is really not acceptable, knowing that I'm going to use this kind of thing on arrays with thousands of elements.

Have you got an idea to do that another way, faster ?

I'm looking for the best way to make dynamic generated condition inside a loop.

A sample worth thousand words so here is my code :

var condition = "data.label == 'Test'";

for (var key in andArray) {
    condition += "&& " + andArray[key];
}

for (var key in orArray) {
    condition += "|| " + orArray[key];
}

var length = dataArray.length;
var result = [];
for (var i = 0; i < length; i++) {
    var data = dataArray[i];
    if (eval(condition)) {
        result.push(obj);
    }
}

I use the eval() function, which works well but that is REALLY too slow ! For a 200 elements array, this code take 25ms to be executed ! This is really not acceptable, knowing that I'm going to use this kind of thing on arrays with thousands of elements.

Have you got an idea to do that another way, faster ?

Share Improve this question edited Aug 3, 2016 at 13:33 Florent Descroix asked Aug 1, 2016 at 17:27 Florent DescroixFlorent Descroix 6115 silver badges14 bronze badges
Add a comment  | 

4 Answers 4

Reset to default 6

I'd like to suggest an alternative solution without string manipulation at all. Instead you can combine functions. Building up code through function composition rather than string manipulation should be less error-prone - and surely less 'hacky' (whatever that means exactly...).

Javascript has first-order functions, you can just pass around (and combine) predicates. A predicate is a function which returns a boolean. For example:

var isLabelTest = function(obj) {
  return obj.label === 'test';
}

Rather than storing conditions as strings, you can store them as predicate functions.
Then you can write some functions which take predicates and return new predicates:

var binaryAnd = function(predA, predB) {
  return function(obj) {
    return predA(obj) && predB(obj);
  };
};

var binaryOr = function(predA, predB) {
  return function(obj) {
    return predA(obj) || predB(obj);
  };
};

You could also write functions which take an array of predicates and combine all predicates in the array into a new predicate:

var and = function(preds) {
  return preds.reduce(binaryAnd, function(obj) {return true;});
};

var or = function(preds) {
  return preds.reduce(binaryOr, function(obj) {return false;});
};

Now given an "andArray" of predicates which all need to return true, and an "orArray" of predicates of which at least one needs to return true, the following code does the job:

var results = [];
var combinedPredicate = binaryAnd(and(andArray), or(orArray));
var pushIfCondition = function (obj) {
  results.push(combinedPredicate(obj));
};
dataArray.forEach(pushIfCondition);

Finally, note that it is not necessary to write those functions for combining predicates yourself, libraries like ramda can provide more efficient implementations.

Create a new Function(), this way the string will be parsed only once:

var length = dataArray.length;
var result = [];
var fn = new Function('data', 'return ' + whereCondition);

for (var i = 0; i < length; i++) {
    var data = dataArray[i];
    if (fn(data)) {
        result.push(obj);
    }
}

Here is a simple trick using filter

Example 1:

> const num = 10
> const rules = []
> rules.push(num > 5)  // true
> rules.push(num % 2 !== 0)  // to check if it is odd number w/c will be "false"
> console.log(rules)
< [true, false]

> rules.filter((rule) => rule === true).length === rules.length
< false  // Did not pass all the conditions

Example 2

> const num = 7
> const rules = []
> rules.push(num > 5)  // true
> rules.push(num % 2 !== 0)  // true
> console.log(rules)
< [true, true]

> rules.filter((rule) => rule === true).length === rules.length
< true  // Passed all the conditions

here is a simple one:

OR dynamic condition

const conditions = [false, 0, 'blah', 1]; // whatever conditions you like

conditions.reduce((previousCond, actualCond) =>  
previousCond || actualCond, false)); // => 'blah'

I like this one because it behave as a real condition and return the real value, not just a boolean.


If you want to return a boolean, you could have used:

conditions.some(cond => cond); // => true

If you want an and condition user Array.every instead of .some

发布评论

评论列表(0)

  1. 暂无评论