复杂但高效的JavaScript数组过滤

复杂但高效的JavaScript数组过滤,javascript,arrays,filtering,Javascript,Arrays,Filtering,我得到了一个非常大的数组,对象(人)的结构是这样的 objects = [ { firstname: 'Jo', lastname : 'Brown' mail: 'jo@brown.com', courses: ['en', 'fr', 'es'] ....and a lot more... }, { firstname: 'Jack', lastname : 'Black' mail: 'blackjack@jac

我得到了一个非常大的数组,对象(人)的结构是这样的

objects = [
  {
    firstname: 'Jo',
    lastname : 'Brown'
    mail: 'jo@brown.com',
    courses: ['en', 'fr', 'es']

    ....and a lot more...
  },
  {
    firstname: 'Jack',
    lastname : 'Black'
    mail: 'blackjack@jackblack.win',
    courses: ['en', 'fr']
    ....and a lot more...
  },
  {
    firstname: 'Jeff',
    lastname : 'Grey'
    mail: 'grey@jeff.co.uk',
    courses: ['es']
    ....and a lot more...
  },

  ...and a lot more...
]
最初,我将另一个数组设置为上面的主数组,该数组应仅包含已过滤的人员:

objectsFiltered = objects;
我需要构建一个函数来过滤数组

  • 应用程序用户在文本字段中键入的字符串(搜索输入)
  • 某些其他条件可通过链接或下拉菜单选择
  • 因此,我将激活的过滤器存储在另一个数组中,如下所示:

    _objectsFilters = [
      {
        property: ['courses']
        value: ['es']
      },
      {
        property: ['firstname', 'lastname', 'mail']
        value: 'userStringInputGoesHere'
      }
    ]
    
    public set objectsFilters(objectsFilters: Array<ObjectsFilters>) {
      for (let filter of objectsFilters) {
        let index = this._objectsFilters.indexOf(filter);
    
        /* add filter if not already active */
        if(index === -1) {
          this._objectsFilters.push(filter);
          continue;
        }
    
        /* remove filter if active already */
        this._objectsFilters.splice(index, 1);
      }
    }
    
    public get objectsFilters(): Array<ObjectsFilters> {
      return this._nobjectsFilter;
    }
    
    objects = [
      {
        firstname: 'Jo',
        lastname : 'Brown'
        mail: 'jo@brown.com',
        courses: ['en', 'fr', 'es']
    
        ....and a lot more...
      },
      {
        firstname: 'Jack',
        lastname : 'Black'
        mail: 'blackjack@jackblack.win',
        courses: ['en', 'fr']
        ....and a lot more...
      },
      {
        firstname: 'Jeff',
        lastname : 'Grey'
        mail: 'grey@jeff.co.uk',
        courses: ['es']
        ....and a lot more...
      },
    
      ...and a lot more...
    ]
    
    _objectsFilters = [
      {
        property: ['courses']
        value: ['es']
      }
    ]
    
    objectsFiltered = [
      {
        firstname: 'Jo',
        lastname : 'Brown'
        mail: 'jo@brown.com',
        courses: ['en', 'fr', 'es']
    
        ....and a lot more...
      },
      {
        firstname: 'Jeff',
        lastname : 'Grey'
        mail: 'grey@jeff.co.uk',
        courses: ['es']
        ....and a lot more...
      },
    
      ...and a lot more...
    ]
    
    inactiveObjects = [
      {
        inactiveCause: {
          property: ['courses'],
          value: ['es']
        },
        /* containing all objects inactive because of the above filter */
        objects: [
          {
            firstname: 'Jack',
            lastname : 'Black'
            mail: 'blackjack@jackblack.win',
            courses: ['en', 'fr']
            ....and a lot more...
          },
        ]
      }
    ]
    
    在本例中,应过滤属性
    课程(数组)
    包含
    es
    且属性
    名字
    姓氏
    邮件
    包含
    UserStringInputGoeSher
    的人员

    我使用函数获取/设置、重置过滤器,如下所示:

    _objectsFilters = [
      {
        property: ['courses']
        value: ['es']
      },
      {
        property: ['firstname', 'lastname', 'mail']
        value: 'userStringInputGoesHere'
      }
    ]
    
    public set objectsFilters(objectsFilters: Array<ObjectsFilters>) {
      for (let filter of objectsFilters) {
        let index = this._objectsFilters.indexOf(filter);
    
        /* add filter if not already active */
        if(index === -1) {
          this._objectsFilters.push(filter);
          continue;
        }
    
        /* remove filter if active already */
        this._objectsFilters.splice(index, 1);
      }
    }
    
    public get objectsFilters(): Array<ObjectsFilters> {
      return this._nobjectsFilter;
    }
    
    objects = [
      {
        firstname: 'Jo',
        lastname : 'Brown'
        mail: 'jo@brown.com',
        courses: ['en', 'fr', 'es']
    
        ....and a lot more...
      },
      {
        firstname: 'Jack',
        lastname : 'Black'
        mail: 'blackjack@jackblack.win',
        courses: ['en', 'fr']
        ....and a lot more...
      },
      {
        firstname: 'Jeff',
        lastname : 'Grey'
        mail: 'grey@jeff.co.uk',
        courses: ['es']
        ....and a lot more...
      },
    
      ...and a lot more...
    ]
    
    _objectsFilters = [
      {
        property: ['courses']
        value: ['es']
      }
    ]
    
    objectsFiltered = [
      {
        firstname: 'Jo',
        lastname : 'Brown'
        mail: 'jo@brown.com',
        courses: ['en', 'fr', 'es']
    
        ....and a lot more...
      },
      {
        firstname: 'Jeff',
        lastname : 'Grey'
        mail: 'grey@jeff.co.uk',
        courses: ['es']
        ....and a lot more...
      },
    
      ...and a lot more...
    ]
    
    inactiveObjects = [
      {
        inactiveCause: {
          property: ['courses'],
          value: ['es']
        },
        /* containing all objects inactive because of the above filter */
        objects: [
          {
            firstname: 'Jack',
            lastname : 'Black'
            mail: 'blackjack@jackblack.win',
            courses: ['en', 'fr']
            ....and a lot more...
          },
        ]
      }
    ]
    
    将现在筛选的人员存储在数组
    objectsFiltered
    **中,并存储由于课程筛选而未激活的剩余人员,如下所示:

    _objectsFilters = [
      {
        property: ['courses']
        value: ['es']
      },
      {
        property: ['firstname', 'lastname', 'mail']
        value: 'userStringInputGoesHere'
      }
    ]
    
    public set objectsFilters(objectsFilters: Array<ObjectsFilters>) {
      for (let filter of objectsFilters) {
        let index = this._objectsFilters.indexOf(filter);
    
        /* add filter if not already active */
        if(index === -1) {
          this._objectsFilters.push(filter);
          continue;
        }
    
        /* remove filter if active already */
        this._objectsFilters.splice(index, 1);
      }
    }
    
    public get objectsFilters(): Array<ObjectsFilters> {
      return this._nobjectsFilter;
    }
    
    objects = [
      {
        firstname: 'Jo',
        lastname : 'Brown'
        mail: 'jo@brown.com',
        courses: ['en', 'fr', 'es']
    
        ....and a lot more...
      },
      {
        firstname: 'Jack',
        lastname : 'Black'
        mail: 'blackjack@jackblack.win',
        courses: ['en', 'fr']
        ....and a lot more...
      },
      {
        firstname: 'Jeff',
        lastname : 'Grey'
        mail: 'grey@jeff.co.uk',
        courses: ['es']
        ....and a lot more...
      },
    
      ...and a lot more...
    ]
    
    _objectsFilters = [
      {
        property: ['courses']
        value: ['es']
      }
    ]
    
    objectsFiltered = [
      {
        firstname: 'Jo',
        lastname : 'Brown'
        mail: 'jo@brown.com',
        courses: ['en', 'fr', 'es']
    
        ....and a lot more...
      },
      {
        firstname: 'Jeff',
        lastname : 'Grey'
        mail: 'grey@jeff.co.uk',
        courses: ['es']
        ....and a lot more...
      },
    
      ...and a lot more...
    ]
    
    inactiveObjects = [
      {
        inactiveCause: {
          property: ['courses'],
          value: ['es']
        },
        /* containing all objects inactive because of the above filter */
        objects: [
          {
            firstname: 'Jack',
            lastname : 'Black'
            mail: 'blackjack@jackblack.win',
            courses: ['en', 'fr']
            ....and a lot more...
          },
        ]
      }
    ]
    
    通过重置某个过滤器,我可以将非活动人员复制回活动人员


    哪条路是正确的道路?

    这看起来像是一个典型的过早优化案例

    在类型A中,始终具有相同的源数据,并且始终对该数据运行一个或多个筛选器。第一个过滤器将是针对完整数据集运行的唯一过滤器;以后的过滤器将针对越来越小的集合运行(因为一些数据已经被过滤掉了)

    在类型B中,每次运行筛选器时都要修改源数据,并将筛选出的元素存储在单独的数组中。正如您所描述的,它将不起作用:如果过滤器发生更改,则无法知道哪些元素需要从存储中恢复到源数组中(因为您无法分辨哪个过滤器删除了每个对象)。我能想到的“最简单”的工作方法是为每个过滤器保留一个单独的存储,因此当filter X发生变化时,您会将filter-by-X的存储中的所有对象转储回源中,然后重新运行filter X。这可以工作,但维护起来相当复杂

    首先编写简单方法的代码。如果没有性能问题,就完成了

    如果您确实存在性能问题,请不要直接跳到方法B:相反,调整执行过滤器的顺序:如果给定的过滤器可能会删除比其他过滤器更多的数据,请先执行。如果一个过滤器在计算上很昂贵,那么最后再做


    如果您仍然存在性能问题,那么您可以进入实现方法B所涉及的英雄(不会是这样的。如果您处理的客户端数据太多,以致于您在过滤它时存在性能问题,那么您已经有了更大的性能问题,只需首先下载它…)这看起来像是一个典型的过早优化案例

    在类型A中,始终具有相同的源数据,并且始终对该数据运行一个或多个筛选器。第一个过滤器将是针对完整数据集运行的唯一过滤器;以后的过滤器将针对越来越小的集合运行(因为一些数据已经被过滤掉了)

    在类型B中,每次运行筛选器时都要修改源数据,并将筛选出的元素存储在单独的数组中。正如您所描述的,它将不起作用:如果过滤器发生更改,则无法知道哪些元素需要从存储中恢复到源数组中(因为您无法分辨哪个过滤器删除了每个对象)。我能想到的“最简单”的工作方法是为每个过滤器保留一个单独的存储,因此当filter X发生变化时,您会将filter-by-X的存储中的所有对象转储回源中,然后重新运行filter X。这可以工作,但维护起来相当复杂

    首先编写简单方法的代码。如果没有性能问题,就完成了

    如果您确实存在性能问题,请不要直接跳到方法B:相反,调整执行过滤器的顺序:如果给定的过滤器可能会删除比其他过滤器更多的数据,请先执行。如果一个过滤器在计算上很昂贵,那么最后再做

    如果您仍然存在性能问题,那么您可能会在实现方法B的过程中遇到困难(不会出现这种情况。如果您处理的客户端数据太多,以致于您在过滤数据时遇到性能问题,那么您在一开始下载数据时就已经遇到了更大的性能问题……

    “类型A”听起来更容易实现。就我个人而言,如果你遇到性能问题,我会走这条路,重新评估IIP。也要考虑的事实是,非常聪明的人已经解决了这些问题很多次,而其他人广泛使用的,经过验证的解决方案几乎总是比我们自己写的更好。(换句话说,用简单的方法来做,如果你发现你需要更强大的东西,不要重新发明轮子。)“A型”听起来更容易实现。就我个人而言,如果你遇到性能问题,我会走这条路,重新评估IIP。也要考虑的事实是,非常聪明的人已经解决了这些问题很多次,而其他人广泛使用的,经过验证的解决方案几乎总是比我们自己写的更好。(换句话说,用简单的方法来做,如果你发现你需要更强大的东西,不要重新发明轮子。)