代码之家  ›  专栏  ›  技术社区  ›  London804

当有多个值时,如何使我的过滤器作为“and”而不是“or”工作?

  •  0
  • London804  · 技术社区  · 6 年前

    我有一个工作的过滤器,有两个限制。

    1:当有多个值时,它作为“或”而不是“和”工作。

    例如

    filterArr = {'claim_number': null, 'status': 'Approved', 'patient': 'John Connor', 'service_date': null}
    
    this.rows = [ 
       { 'claim_number': 1234, 'status': 'Approved', 'patient': 'John Connor', 'service_date': '1/10/2018', etc ...}
       { 'claim_number': 4567, 'status': 'Approved', 'patient': 'James Brown', 'service_date': '3/11/2018', etc ...}
       { 'claim_number': 7890, 'status': 'Approved', 'patient': 'Steven Hawkins', 'service_date': '2/1/2018', etc ...}
    

    目前,所有这些项目都将匹配,因为只有第一个项目同时具有“状态:已批准”和“患者:John Connor”。

    2:第二个限制是,当有一个部分字符串与this.rows中的完整字符串匹配时,我想触发匹配。

    例如

    filterArr = {'claim_number': 12, 'status': 'Approved', 'patient': null, 'service_date': null}
    
    this.rows = [ 
        { 'claim_number': 1234, 'status': 'Approved', 'patient': 'John 
           Connor', 'service_date': '1/10/2018', etc ...}
        { 'claim_number': 4567, 'status': 'Approved', 'patient': 'James 
           Brown', 'service_date': '3/11/2018', etc ...}
        { 'claim_number': 7890, 'status': 'Approved', 'patient': 'Steven Hawkins', 'service_date': '2/1/2018', etc ...}
    

    同样,只有数字1应匹配,因为它包含正确的“状态”和“索赔编号”中的前两位数字。

    这应该是相对简单的,因为我在传递一个特定的键时让它工作,但是现在过滤器是动态的,它似乎不能正常工作。

    我附上了 jsFiddle 尽管它没有正确执行,但我在一个角度项目中使用了反应式形式,因此仅供参考。此外,请仅包括使用ES5或ES6解决的答案。我不能使用flatmap()和其他实验特性。谢谢您。

    2 回复  |  直到 6 年前
        1
  •  1
  •   Akrion    6 年前

    看看这是否对你有用:

    const rows = [ { 'claim_number': '1234', 'status': 'Approved', 'patient': 'John Connor', 'service_date': '1/10/2018'}, { 'claim_number': '4567', 'status': 'Approved', 'patient': 'James Brown', 'service_date': '3/11/2018'}, { 'claim_number': '7890', 'status': 'Approved', 'patient': 'Steven Hawkins', 'service_date': '2/1/2018'} ]
    
    const filtrate = (i, f) => {
      const vals = Object.values(f).reduce((r,c) => (!!c ? r.push(c) : 0, r), [])
      return vals.every(x => Object.values(i).some(y => y.includes(x)))
    }
    const filterBy = (arr, f) => arr.filter(x => filtrate(x, f))
    
    console.log(filterBy(rows, {'claim_number': null, 'status': 'Approved', 'patient': 'John Connor', 'service_date': null}))
    console.log(filterBy(rows, {'claim_number': '12', 'status': 'Approved', 'patient': null, 'service_date': null}))

    想法是先 clean/sanitize 过滤对象,一旦你只有干净的值,然后通过 Array.every 和; Array.some 和; Array.includes .

    另外请注意,我将数字转换为字符串,因为如果要搜索 12 是其中的一部分 1234 等。

    为了清晰起见,这里扩展了相同的代码:

    const rows = [ { 'claim_number': '1234', 'status': 'Approved', 'patient': 'John Connor', 'service_date': '1/10/2018'}, { 'claim_number': '4567', 'status': 'Approved', 'patient': 'James Brown', 'service_date': '3/11/2018'}, { 'claim_number': '7890', 'status': 'Approved', 'patient': 'Steven Hawkins', 'service_date': '2/1/2018'} ]
    
    const filtrate = (item, filter) => {
      const values = Object.values(filter).reduce((accumulator, current) => {
      if(!!current)
        accumulator.push(current) 
        return accumulator
      }, [])
      return values.every(value => {
        return Object.values(item).some(itm => itm.includes(value))
      })
    }
    const filterBy = (allRows, filterObject) => {
      return allRows.filter(row => filtrate(row, filterObject))
    }
    
    console.log(filterBy(rows, {'claim_number': null, 'status': 'Approved', 'patient': 'John Connor', 'service_date': null}))
    console.log(filterBy(rows, {'claim_number': '12', 'status': 'Approved', 'patient': null, 'service_date': null}))
        2
  •  0
  •   London804    6 年前

    这就是我最终使用的答案。我觉得这是最直接的。

    @Input() filters: Array<any>;
    allRows: Array<any> = [];
    
    applyFilters() {
        this.rows = this.allRows;
    
        this.rows = this.rows.filter(row => {
            for (let filter of this.filters) {
                const filterVal = this.filtersForm.get(filter.key).value;
                const rowVal = row[filter.key];
    
                if (!!filterVal && rowVal.toString().toLowerCase().includes(filterVal.toString().toLowerCase())) {
                    return true;
                }
            }
    
            return false;
        })
    }