如何在JavaScript中有条件地合并列表中的一些元素?

时间:2016-01-21 16:59:55

标签: javascript lodash

我正在构建这个Builder模式,我想将列表中的一些元素合并在一起。但我想以更清洁的方式做到这一点。这是我到目前为止所提出的有效但我确信有更好的方法来做到这一点。

function FiltersBuilder() {
  this.filters = [];
};

FiltersBuilder.prototype.addFilter = function(options) {
  var filter = {
    'type': 'selector',
    'dimension': options.dimension,
    'value': options.value
  }
  this.filters.push(filter);
  return this;
}

FiltersBuilder.prototype.addRegexFilter = function(options) {
  var filter = {
    'type': 'regex',
    'dimension': options.dimension,
    'pattern': options.value
  }
  this.filters.push(filter);
  return this;
}

FiltersBuilder.prototype.not = function() {
  var not = {
    'type': 'not'
  };
  this.filters.push(not);
  return this;
}

FiltersBuilder.prototype.getFilters = function() {
  var result = [];
  this.filters.forEach(function each(filter, index, theFilters) {
    if (filter.type === 'not') {
      var filterToMerge = theFilters[index + 1];
      var mergedFilter = _.merge(filter, {field: filterToMerge});
      result.push(mergedFilter);
    } else {
        if(index > 0) {
        notFilter = theFilters[index - 1];
        if(notFilter.type === 'not') {
            return;
        }
      }
      result.push(filter);
    }
  });

  return result;
}

var filterBuilder = new FiltersBuilder();
filterBuilder.addFilter({
  dimension: '_o',
  value: 'origin'
});
filterBuilder.not().addRegexFilter({
  dimension: 'cTy',
  value: 'value'
});

console.log(filterBuilder.getFilters());

如果在添加过滤器之前调用了not方法,我想将not过滤器与下一个元素合并,并将该对象添加到result列表中。但是,如果在添加过滤器之前未调用not,则不要执行任何操作,只需将过滤器添加到result列表。

https://jsfiddle.net/9wyqbovu/

2 个答案:

答案 0 :(得分:3)

不是将not视为要添加到过滤器列表中的过滤器,而是在获得过滤器时进行处理,而是将其视为修饰符 - 标记。在not对象上维护FiltersBuilder属性,初始化为false,对FilterBuilders.not的调用将切换为not。在每个过滤器上,还要添加not属性,该属性由FilterBuilders上的function FiltersBuilder() { this.filters = []; this.not = false; }; FiltersBuilder.prototype.addFilter = function(options) { var filter = { 'type': 'selector', 'dimension': options.dimension, 'value': options.value, not: this.not } this.not = false; this.filters.push(filter); return this; } FiltersBuilder.prototype.addRegexFilter = function(options) { var filter = { 'type': 'regex', 'dimension': options.dimension, 'pattern': options.value, not: this.not } this.not = false; this.filters.push(filter); return this; } FiltersBuilder.prototype.not = function() { this.not = !this.not; } FiltersBuilder.prototype.getFilters = function() { return this.filters; } var filterBuilder = new FiltersBuilder(); filterBuilder.addFilter({ dimension: '_o', value: 'origin' }); filterBuilder.not().addRegexFilter({ dimension: 'cTy', value: 'value' }); console.log(filterBuilder.getFilters()); 标志的当前值设置(然后重置)。换句话说:

filterBuilder.not.addFilter

如果您希望能够说notnot后没有括号),请将Object.defineProperty(FiltersBuilder.prototype, "not", { get: function() { this.not = !this.not; return this; } }); 定义为吸气剂,即

{{1}}

答案 1 :(得分:2)

那么,如果我们从右侧迭代它并使用unshift而不是push怎么样:

getFilters = function(){
    return this.filters.reduceRight(function(results, filter){
        if(filter.type === 'not'){
           //get filter to 'not'
           var notFilter = results[0];
           Object.assign(notFilter, filter); //Or _.merge
        } else {
           results.unshift(filter);
        }
        return results;
    }, []);
}

或者,您可以使用push代替unshift,抓取数组的最后一个元素作为否定的过滤器(而不是第一个)并反转结果。

getFilters = function(){
    return this.filters.reduceRight(function(results, filter){
        if(filter.type === 'not'){
           //get filter to 'not'
           var notFilter = results[results.length - 1];
           Object.assign(notFilter, filter); //Or _.merge
        } else {
           results.push(filter);
        }
        return results;
    }, []).reverse();
}