Javascript 如何从任何对象键筛选对象数组中不区分大小写的匹配项

Javascript 如何从任何对象键筛选对象数组中不区分大小写的匹配项,javascript,arrays,search,filtering,Javascript,Arrays,Search,Filtering,我这里有一个示例代码,我正在尝试过滤匹配的对象,而不会影响代码的复杂性或性能: 这里的代码根据一个显式定义的键筛选匹配项,并且不区分大小写 const people=[ {姓:“鲍勃”,姓:“史密斯”,状态:“单身”}, {名字:'bobby',姓氏:'SuxatCapitalizating',状态:'single'}, {姓:“吉姆”,姓“约翰逊”,状态“复杂”}, {firstName:'Sally',lastName:'Fields',status:'relationship'}, {姓

我这里有一个示例代码,我正在尝试过滤匹配的对象,而不会影响代码的复杂性或性能:

这里的代码根据一个显式定义的键筛选匹配项,并且不区分大小写

const people=[
{姓:“鲍勃”,姓:“史密斯”,状态:“单身”},
{名字:'bobby',姓氏:'SuxatCapitalizating',状态:'single'},
{姓:“吉姆”,姓“约翰逊”,状态“复杂”},
{firstName:'Sally',lastName:'Fields',status:'relationship'},
{姓氏:“罗伯特”,姓氏:“波波勒”,状态:“单身”},
{名字:“约翰尼”,姓氏:“约翰森”,状态:“复杂”},
{姓氏:'Whaley',姓氏:'McWhalerson',状态:'relationship'
rogueBonusKey:“鲍勃喜欢鲑鱼”},
]
const searchString='Bob'
const found=people.filter((person)=>{
如果(person.firstName==searchString)返回true
})

log(found)
如果我们假设所有属性都是字符串,那么您可以按以下方式执行

const people = [
  // ...
]

const searchString = 'Bob'

const filterBy = (term) => {
  const termLowerCase = term.toLowerCase()
  return (person) =>
    Object.keys(person)
      .some(prop => person[prop].toLowerCase().indexOf(termLowerCase) !== -1)
}

const found = people.filter(filterBy(searchString))

console.log(found)
更新:使用RegExp和更多老式软件的替代解决方案:),但速度快了2倍

const people = [
  // ...
]

const searchString = 'Bob'

const escapeRegExp = (str) => // or better use 'escape-string-regexp' package
  str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&")


const filterBy = (term) => {
  const re = new RegExp(escapeRegExp(term), 'i')
  return person => {
    for (let prop in person) {
      if (!person.hasOwnProperty(prop)) {
        continue;
      }
      if (re.test(person[prop])) {
        return true;
      }
    }
    return false;        
  }
}

const found = people.filter(filterBy(searchString))

如果整个匹配对象是预期结果,则可以使用
for..of
循环,
对象.values()
数组.prototype.find()


您需要过滤数组,然后过滤对象中的每个键以匹配正则表达式。本例将问题分解为单个责任函数,并将其与函数概念(例如)联系起来

性能测试包括在内,在chrome中,这始终比Dmitry的示例更快。我没有测试过任何其他浏览器。这可能是因为chrome进行了优化,使jit能够更快地处理脚本,而代码被表示为只将一种类型的数据作为输入,将一种类型的数据作为输出的小型单一责任函数

由于测试的原因,加载大约需要4秒钟

const people=[
{姓:“鲍勃”,姓:“史密斯”,状态:“单身”},
{名字:'bobby',姓氏:'SuxatCapitalizating',状态:'single'},
{姓:“吉姆”,姓“约翰逊”,状态“复杂”},
{firstName:'Sally',lastName:'Fields',status:'relationship'},
{姓氏:“罗伯特”,姓氏:“波波勒”,状态:“单身”},
{名字:“约翰尼”,姓氏:“约翰森”,状态:“复杂”},
{名字:'Whaley',姓氏:'McWhalerson',状态:'relationship',rogueBonusKey:'bob喜欢鲑鱼'},
]
//对对象的每个键运行谓词函数
//常数hasValue=f=>o=>
//key(o).some(x=>f(o[x]))
常数hasValue=f=>o=>{
让钥匙
用于(输入o){
如果(f(o[key])返回true
}
返回错误
}
//将字符串转换为正则表达式
const toReg=str=>
新的RegExp(str.replace(//\//g,//'),'gi')
//使用正则表达式测试字符串
常量匹配=reg=>x=>
注册测试(x)
//按谓词筛选数组
//常量过滤器=f=>a=>a.filter(a)
常量过滤器=f=>a=>{
常量ret=[]
设ii=0
设ll=a.length
对于(;ii{
//根据搜索值创建正则表达式
//为所有过滤器迭代缓存它
const reg=toReg(值)
//过滤你的人群
回流过滤器(
//仅返回与正则表达式匹配的结果
hasValue(匹配(注册))
)
}
//创建一个函数以按值“bob”进行筛选
常量filterBob=filterArrByValue('Bob')
//摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩##############//
assert('hasValue找到一个匹配的值',!!hasValue(x=>x=='one')({one:'one'}))
assert('toReg是一个正则表达式',toReg('reg')instanceof RegExp)
assert('match在字符串中查找正则表达式',!!match(/test/)('this is a test'))
assert('filter filters a array',filter(x=>x==true)([true,false])。length==1)
//关于现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场现场##############//
console.log(
//运行传递人员数组的函数
“找到鲍勃”,
filterBob(人)
)
console.log(
//或者你可以同时给他们两个打电话
“找到鲑鱼”,
filterArrByValue(“鲑鱼”)(人)
)
//摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩摩##############//
//德米特里的第一个函数
常量过滤器比=(术语)=>{
const termLowerCase=term.toLowerCase()
返回(人)=>
对象。键(人)
.some(prop=>person[prop].toLowerCase().indexOf(termLowerCase)!=-1)
}
//dmitry的更新函数
const escapeRegExp=(str)=>//或者更好地使用“escape string regexp”包
str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\^\$\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
常数filterBy2=(项)=>{
const re=new RegExp(escapeRegExp(术语),'i')
返回人=>{
为了(让道具亲自支撑){
如果(!个人拥有自己的财产(道具)){
继续;
}
如果(重新测试(人员[道具]){
返回true;
}
}
返回false;
}
}
//测试stringify-非常慢
常量fuzzyMatch=(集合,搜索项)=>
collection.filter((obj)=>JSON.stringify(obj)
.toLowerCase()
.indexOf(searchTerm.toLowerCase())!=-1
)
新基准({迭代次数:1000000})
//测试我的功能-最快
.add('synthet1c',function(){
filterBob(人)
})
.add('dmitry',function(){
people.filter(filterBy('Bob'))
})
.add('dmitry2',函数(){
people.filter(filterBy2('Bob'))
})
.add('guest',function()){
fuzzyMatch(人物“Bob”)
})
.run()

你应该给fusejs一次机会。 它有一些有趣的设置,例如threshold,它允许一些输入错误(0.0=完美,1.0=匹配任何内容)和
keys
指定要搜索的任何键

const people = [
  { firstName: 'Bob', lastName: 'Smith', status: 'single' },
  { firstName: 'bobby', lastName: 'Suxatcapitalizing', status: 'single' },
  { firstName: 'Jim', lastName: 'Johnson', status: 'complicated' },
  { firstName: 'Sally', lastName: 'Fields', status: 'relationship' },
  { firstName: 'Robert', lastName: 'Bobler', status: 'single' },
  { firstName: 'Johnny', lastName: 'Johannson', status: 'complicated' },
  { firstName: 'Whaley', lastName: 'McWhalerson', status: 'relationship'
    rogueBonusKey: 'bob likes salmon' },
]

const fuseOptions = {
  caseSensitive: false,
  shouldSort: true,
  threshold: 0.2,
  location: 0,
  distance: 100,
  maxPatternLength: 32,
  minMatchCharLength: 1,
  keys: [
    "firstName",
    "lastName",
    "rogueBonusKey",
  ]
};


const search = (txt) => {
  const fuse = new Fuse(people, fuseOptions);
  const result = fuse.search(txt);
  return result;
}
您还可以使用with
i
modifier来执行案例插入
const people = [
  { firstName: 'Bob', lastName: 'Smith', status: 'single' },
  { firstName: 'bobby', lastName: 'Suxatcapitalizing', status: 'single' },
  { firstName: 'Jim', lastName: 'Johnson', status: 'complicated' },
  { firstName: 'Sally', lastName: 'Fields', status: 'relationship' },
  { firstName: 'Robert', lastName: 'Bobler', status: 'single' },
  { firstName: 'Johnny', lastName: 'Johannson', status: 'complicated' },
  { firstName: 'Whaley', lastName: 'McWhalerson', status: 'relationship'
    rogueBonusKey: 'bob likes salmon' },
]

const fuseOptions = {
  caseSensitive: false,
  shouldSort: true,
  threshold: 0.2,
  location: 0,
  distance: 100,
  maxPatternLength: 32,
  minMatchCharLength: 1,
  keys: [
    "firstName",
    "lastName",
    "rogueBonusKey",
  ]
};


const search = (txt) => {
  const fuse = new Fuse(people, fuseOptions);
  const result = fuse.search(txt);
  return result;
}