【问题标题】:How to make a search function that search an array如何制作搜索数组的搜索功能
【发布时间】:2017-10-14 11:46:28
【问题描述】:

我有一个这样的对象数组,我如何在这个对象数组中搜索特定的字符串模式?

如果我输入 'B' 结果应该是 'bent' 和 'benny

如果我输入 'benn' 结果应该是 'benny'

HTML

<form>
    <input id="getCoins" type="text" name="getCoins" placeholder="">
</form>

JavaScript

var input = document.getElementById("getCoins");
var arr = [0:{name: 'bent', town: 'kansas'}1:{ name:'benny', town:'vegas'}]
input .addEventListener("keyup", function(e){
    console.log(filterIt(arr, input.value));
}

这是我在另一篇文章中尝试过的,但我无法让它工作?

function filterIt(arr, searchKey) {
    return arr.filter(function (obj) {
        return Object.keys(obj).some(function (key) {
            return obj[key].includes(searchKey);
        })
    });
}

注意:我只想搜索名称,而不是城镇

【问题讨论】:

  • “我无法让它工作” - 它根本不起作用?它有效,但不正确?
  • 这是错误的:var arr = [0:{name: 'bent', town: 'kansas'}1:{ name:'benny', town:'vegas'}]。应该是:var arr = [ {name: 'bent', town: 'kansas'}, {name:'benny', town:'vegas'} ];

标签: javascript arrays object search


【解决方案1】:

您首先定义一个函数来确定给定一个单个项目的过滤条件。如果项目应该被包含,这个函数应该返回一个布尔值。

function match(inputValue, item) { /* .... */ }

那么你可以在Array.prototype.filter()函数中使用这个函数,如下所示:

var matchingValues = arr.filter(match.bind(null, input.value));

由于match() 函数接受两个参数,但filter() 一次只传递其回调一项,我们partially apply 使用bind()input.value 匹配函数将match() 函数转换为一个函数 那只会期望该项目。

这和做的一样:

var matchingValues = arr.filter(function (item) { 
  return match(input.value, item); 
});

我发现如果使用部分应用程序,代码看起来更整洁,更容易理解。

哦,其中一位评论者指出,OP 只想要 name 部分。在这种情况下,只需链接 .map() 调用即可提取名称:

var matchingNames = arr
  .filter(function (item) { 
    return match(input.value, item); 
  })
  .map(function (item) {
    return item.name;
  });

编辑:您还应该修复数组:

var arr = [{name: 'bent', town: 'kansas'}, { name:'benny', town:'vegas'}]

我建议花一些时间来设置 ESLint 并将其集成到您的编辑器中,这样您的代码看起来就很漂亮,并且至少没有语法错误。

【讨论】:

  • 这是因为我正在检索一个 json 对象,我将其推送到这样的数组中 var coins = []; for (var l in jsonObj) { coins.push(jsonObj[l]); }
  • 不过,您的代码 sn-p 在现实生活中会产生语法错误。
【解决方案2】:
function filterIt(arr, searchKey) {
    return arr.filter(function (obj) {
        return obj.name.search(searchKey) != -1;
    });
}

【讨论】:

  • 他不想只搜索name,他想搜索所有属性。
【解决方案3】:

您可以使用forEach 遍历数组,然后使用for..in 遍历每个对象。在函数顶部声明一个数组,然后将任何匹配项推入数组并返回。

function findMatches(arr, searchString){
  const matches = [];

  arr.forEach((obj) => {
    for (const key in obj) {
      if (obj[key].includes(searchString)){
        matches.push(obj[key]);
      }
    }
  });

  return matches;
}

const arr = [
  {name: 'bent', town: 'kansas'},
  {name:'benny', town:'vegas'}
];

console.log(findMatches(arr, "b"));
// => ["bent", "benny"]

console.log(findMatches(arr, "benn"));
// => ["benny"]

【讨论】:

  • 您可以使用filter() 一次性完成所有操作,而不是使用forEach() 和累加器数组。您可以使用此表达式来测试obj 是否匹配:@ 987654328@
  • 你确定?这只是为我返回两个空数组。
  • 啊,对,我错过了return。谢谢。不过有两点:这会返回整个对象,我理解 OP 正在搜索特定的字符串。此外,当我在 6 个月或其他时间重新访问此代码时,使用更详细的版本,我会立即知道我在做什么,而使用更简洁的版本,我将不得不重新考虑该功能以记住什么它在做。感谢您提供它。这是赞赏:)
  • 无论是返回整个对象还是只返回一个字符串,修改起来都很简单。至于你能不能知道代码是做什么的,就看你到时候是否还保持目前的 JS 流畅度。一旦你掌握了过滤器、地图等,很确定这种模式会变得不费吹灰之力。
【解决方案4】:

更优化的解决方案是预先提取初始的 name/town 词。然后,在每个 keyup 事件上 - 仅在该字符串中搜索。

RegExp 对象和String.match() 函数的解决方案:

var input = document.getElementById("getCoins"),
    arr = [{name: 'bent', town: 'kansas'},{ name:'benny', town:'vegas'}],
    item_str = arr.map((o) => Object.values(o).join(' ')).join(' ');

input.addEventListener("keyup", function(e){
    var pat = new RegExp('\\w*'+e.target.value+'\\w*', 'gi');
    console.log(item_str.match(pat));
});
<form>
    <input id="getCoins" type="text" name="getCoins" placeholder="">
</form>

【讨论】:

    猜你喜欢
    • 2019-04-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-04-03
    • 2015-07-30
    • 2018-10-02
    • 2022-09-27
    相关资源
    最近更新 更多