javascript - 如何为来自任何对象键的不区分大小写的匹配项过滤对象数组

标签 javascript arrays search filtering

我这里有这个示例代码,我试图在不增加代码复杂性或性能的情况下过滤匹配的对象:

此处的代码根据一个明确定义的键过滤匹配项,并且不区分大小写。

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 searchString = 'Bob'

const found = people.filter((person) => {
  if (person.firstName === searchString) return true
})

console.log(found)

目标:

  1. 我希望它不区分大小写
  2. 我希望它从任意键返回匹配项
  3. 我希望它使用 contains 不完全匹配来查找

像这样:

// 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 searchString = 'bob'

// ... magic

// console.log(found)

// { firstName: 'Bob', lastName: 'Smith', status: 'single' },
// { firstName: 'bobby', lastName: 'Suxatcapitalizing', status: 'single' },
// { firstName: 'Robert', lastName: 'Bobler', status: 'single' },
// { firstName: 'Whaley', lastName: 'McWhalerson', status: 'relationship'
//   rogueBonusKey: 'bob likes salmon' },

我已经搜索了与 Array.filter() 相关的文档,我绝对可以制定涉及 Array.reduce() 并使用 循环内容的解决方案Object.keys(obj).forEach(),但我想知道是否有一种简洁、高效的方式来处理这种模糊搜索。

像这样:

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 searchString = 'Bob'

const found = people.filter((person) => {
  if (person.toString().indexOf(searchString).toLowerCase !== -1) return true
})

console.log(found)

[edit] This definitely works, but is it acceptable?

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 searchString = 'Bob'

const found = people.filter((person) => {
  const savageMatch = JSON.stringify(person)
    .toLowerCase()
    .indexOf(searchString.toLowerCase()) !== -1

  console.log(savageMatch)
  if (savageMatch) return true
})

console.log(found)

内存占用优化:

const found = people.filter((person) => JSON.stringify(person)
    .toLowerCase()
    .indexOf(searchString.toLowerCase()) !== -1
)

转换为函数:

const fuzzyMatch = (collection, searchTerm) =>
  collection.filter((obj) => JSON.stringify(obj)
    .toLowerCase()
    .indexOf(searchTerm.toLowerCase()) !== -1
)

console.log(fuzzyMatch(people, 'bob'))

这里有一些很好的答案;到目前为止,我选择这个是为了满足我的过滤需求:

const people = [
  { imageURL: 'http://www.alice.com/goat.jpeg', 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: 'Ronald', lastName: 'McDonlad', status: 'relationship',
    rogueBonusKey: 'bob likes salmon'
  },
  {
    imageURL: 'http://www.bob.com/cats.jpeg', firstName: 'Whaley', lastName: 'McWhalerson', status: 'relationship',
    rogueBonusKey: 'bob hates salmon'
  },
]

const searchString = 'bob'

const options = {
  caseSensitive: false,
  excludedKeys: ['imageURL', 'firstName'],
}

const customFind = (collection, term, opts) => {
  const filterBy = () => {
    const searchTerms = (!opts.caseSensitive) ? new RegExp(term, 'i') : new RegExp(term)
    return (obj) => {
      for (const key of Object.keys(obj)) {
        if (searchTerms.test(obj[key]) &&
          !opts.excludedKeys.includes(key)) return true
      }
      return false
    }
  }
  return collection.filter(filterBy(term))
}

const found = customFind(people, searchString, options)

console.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))

关于javascript - 如何为来自任何对象键的不区分大小写的匹配项过滤对象数组,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47117868/

相关文章:

javascript - mustache 在服务器(rails)和客户端(javascript)上呈现

javascript - 在服务器重新加载时,将 CodeMirror 与 Vuejs/Nuxtjs 一起使用会导致错误 'CodeMirror' is not defined

c++ - 访问基类型数组成员(Int-to-Type 习语)

c - (int) 转换如何作用于 char 数组和 char *?

c# - 从多个列表或数组中搜索/过滤(可能数十亿)项目组合的最佳方式

javascript - 检查最后一个字符是否为点 (.)

javascript - 用CSS绘制水容器

c - C语言中如何计算字符串数组元素的个数?

python - 在数组数组中查找数组索引的快速方法

search - Emacs 组织模式 : How to find all TODOs that don't have a deadline specified