【问题标题】:Search filter with multiple values on multiple fields在多个字段上具有多个值的搜索过滤器
【发布时间】:2017-02-02 21:14:14
【问题描述】:

基本上,我需要返回真/假的代码,以判断是否在 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 行 (在第 1 行和第 2 行的 3 列中至少有一个找到了“PO1”和“ABC”,对于第 3 行,找到了“PO1”,但没有在任何列中找到“ABC”)

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

至于代码本身,我有一个搜索词数组(我将输入的文本用空格分隔),称为searchTerms。每个字段的值都是通过item.Attributes.[fieldname].content来访问的,比如item.Attributes.PONUM.content等。

我尝试了以下 recursive 方法,理论上该方法应该可行,但在浏览器中出现“最大堆栈调用”错误。

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)

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

或者至少那是我认为我的函数应该做的;)

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

【问题讨论】:

  • 好的,对于初学者来说,indexOf(searchTerms[x] != -1) 可能没有按照您的预期进行。
  • 另一件事,您可能想在这些行中递减 xsearch(searchTerms,x++)
  • 顺便说一句。你的方法很有趣,但我真诚地相信,传统的循环(或 Timo 的函数式方法)将来会减少头部划伤。
  • 抱歉 x++ 实际上是 x--,我只是复制了错误的代码。固定

标签: javascript arrays filter


【解决方案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));
    );

【讨论】:

  • 如果搜索词是 PO10,即使它不应该返回匹配项。
  • @ibrahimmahrir 这些术语会匹配第一行,应该没问题吧?
【解决方案2】:

只需使用 mapreduce 函数(来自 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 workcodepen

时间复杂度 = O(n)

内存复杂度 = O(n)


说明:

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

拆分后我们得到了数组

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

让我们计算我们的列表,其中 filterjoin 都需要在一个文件中填写。

第一关:

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

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

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

and reduce 联合true的布尔结果数组(联合的中性值)

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

结果“PO10 ABC ABCCOMPANY”与查询“PO1 XYZ”不匹配。我们不显示它。

第三遍:

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

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

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

and reduce 联合true的布尔结果数组(联合的中性值)

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

结果“PO12 GHI XYZCOMPANY”与查询“PO1 XYZ”匹配。我们展示它。

【讨论】:

    猜你喜欢
    • 2016-11-07
    • 1970-01-01
    • 2017-11-06
    • 2019-04-23
    • 1970-01-01
    • 2020-11-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多