搜索多个字段上具有多个值的过滤器

时间:2017-02-02 21:14:15

标签: javascript arrays filter

基本上我需要返回true / false的代码,该代码是否在Javascript对象的3个字段中找到所有搜索字符串(以过滤列表视图)。

此代码将针对列表视图的每个元素执行,以确定它是否应保留在列表中或被过滤掉。每个元素包含3个字段(PONUM,DESCRIPTION和VENDOR)。用户可以在文本框中键入一个或多个搜索词,我想确保键入的每个词都出现在至少一个字段中。

元素的示例列表:

[ROW] | PONUM | DESCRIPTION | VENDOR
1     | PO10  | ABC         | ABCCOMPANY
2     | PO11  | DEF         | ABCCOMPANY
3     | PO12  | GHI         | XYZCOMPANY
4     | PO20  | JKL         | XYZCOMPANY

如果我输入以下过滤条件:PO1 ABC

我应该看到第1行和第2行但不是3行 (" PO1" AND" ABC"在第1行和第2行的3列中的至少一列中找到,第3行," PO1和#34;被找到,但是" ABC"不在任何栏目中

如果我输入:PO1 XYZ,我只能看到第3行。 如果我输入:PO2 ABC,我什么也看不见。

至于代码本身,我有一系列搜索术语(我将输入的文本输入并将其拆分为空格),称为searchTerms。使用item.Attributes。[fieldname] .content(例如item.Attributes.PONUM.content等)访问每个字段的值。

我尝试了以下理论应该有效的递归方法,但是我得到了一个最大的堆栈调用"浏览器中的错误。

function search(searchTerms,x,item) {
    if(x < 0) { 
        return true;
    }
    if(item.Attribute.PONUM.content.indexOf(searchTerms[x] != -1) {
        return search(searchTerms,x--);
    }
    if(item.Attribute.DESCRIPTION.content.indexOf(searchTerms[x] != -1) {
        return search(searchTerms,x--);
    }
    if(item.Attribute.VENDOR.content.indexOf(searchTers[x]) != -1) {
        return search(searchTerms,x--)
    }
    return false;
}

//Function is called like this:
return search(searchTerms,searchTerms.length-1,item)

基本上它通过搜索词走(向后)。如果它在其中一个字段中找到它,则会再次使用下一个搜索项(x--)调用搜索。如果它没有找到它,它会立即返回false(现在将过滤该项目)。如果它继续在其中一个字段中找到每个搜索项,它最终将达到-1(搜索项的结尾)并返回true,因为它在其中一个字段中找到了所有搜索项。

或至少是我认为我的功能应该做的事情;)

非常感谢任何和所有帮助!

2 个答案:

答案 0 :(得分:1)

稍微不同的方法可能会在这里找到更清晰的解决方案:

function search(terms, item) {
    return terms.every(function(term) {
        return ['PONUM', 'DESCRIPTION', 'VENDOR'].some(function(attribute) {
            return item.Attributes[attribute].indexOf(term) !== -1;
        });
    });
}

有关everysome的更多信息。

像箭头函数这样的ES6功能可以提供更好的语法:

const search = (terms, item) =>
    terms.every(term =>
        ['PONUM', 'DESCRIPTION', 'VENDOR']
            .some(attribute => item.Attributes[attribute].includes(term));
    );

答案 1 :(得分:0)

只需使用地图减少功能(来自 lodash )。在您必须加入所有必填字段之前。

filteredList: function () {
    let query = _.split(_.trim(this.input), ' ')
    return this.list.filter(function (comp) {
      let row = _.join([comp.ponum, comp.description,  comp.vendor], ' ')
      let result = _.map(query, function (part) {
        if (part === '') return true
        return row.indexOf(part) !== -1
      })
      return _.reduce(result, function (x, y) {
        return x & y
      }, true)
    })
  }

这是how it work codepen

  

时间复杂度= O(n)

     

内存复杂度= O(n)

<强>解释

我们收到了搜索查询:"PO1 XYZ"

拆分之后,我们得到了

let query = split("PO1 XYZ") => ['PO1', 'XYZ']

计算我们的列表,其中包含过滤器加入所有必需的文件。

第一遍:

join(["PO10", "ABC", "ABCCOMPANY"], " ") => "PO10 ABC ABCCOMPANY"

我们的查询数组映射到像这样的布尔数组

['PO1', 'XYZ'] => ["PO10 ABC ABCCOMPANY".indexOf('PO1') => true, "PO10 ABC ABCCOMPANY".indexOf('XYZ') => false] => [true, false]

通过连接 / em>的)

true & true & false => ((true & true) & false) => false

结果&#34; PO10 ABC ABCCOMPANY&#34;不与查询&#34; PO1 XYZ&#34;匹配。我们没有表现出来。

第三关:

join(["PO12", "GHI", "XYZCOMPANY"], " ") => "PO12 GHI XYZCOMPANY"

我们的查询数组映射到像这样的布尔数组

['PO1', 'XYZ'] => ["PO12 GHI XYZCOMPANY".indexOf('PO1') => true, "PO12 GHI XYZCOMPANY".indexOf('XYZ') => true] => [true, true]

通过连接 / em>的)

true & true & true => ((true & true) & true) => true

结果&#34; PO12 GHI XYZCOMPANY&#34;与查询&#34; PO1 XYZ&#34;匹配。我们展示它。