【问题标题】:search for an input in an array returning the reverse of the search input在数组中搜索一个输入,返回搜索输入的逆向
【发布时间】:2021-12-06 17:27:48
【问题描述】:

我正在寻找一种在数组中搜索名称的方法,包括搜索输入(多个单词:名字、姓氏)可能被颠倒的情况。

数组看起来像这样,带有一系列名称。

const names = ['Alan Hope', 'Greg Day', 'Alan Peters']

搜索输入可能如下'peter Al'

实现这一点的代码是什么样的。这是我目前所拥有的,我知道这是完全错误的。


const studentNames = ['Alan Hope', 'Greg Day', 'Alan Peters']

function search () {
  const bankingSheet = ss.getSheetByName('Banking')
  const searchInput = 'Hope Al'
  const searchWords = searchInput.split(/\s+/)

  const filtered = studentNames.filter(function(name) {
    searchWords.every(function(word) {
      return name.toString().toLowerCase().indexOf(word) !== -1
    })  
})
Logger.log(filtered)
}

根据我收集的信息,我需要首先将搜索输入拆分为组成词。然后我需要过滤名称数组。对于数组中的每个名称,我需要检查是否所有搜索词都以某种方式出现在名称中。我认为这可能涉及every方法。

对于每个名字,如果返回值为真,那就是我需要返回的。

这种想法正确吗?

提前感谢您!这一刻真的很头疼!

【问题讨论】:

  • 从给定数组中搜索“Hope Al”将要求提升到一个新的水平,请查看Levenshtein distance;
  • @Teemu 读后听起来真的很复杂。这个问题对于像我这样的业余爱好者来说是不是太大了?
  • 我无法回答这个问题,你必须自己定义你的技能。您可以即时创建正则表达式,并检查关键字是否部分匹配数据。但是,这很容易出错,而且很容易得到误报。我建议使用唯一的 id 或类似的东西。

标签: javascript arrays google-apps-script


【解决方案1】:

这个想法是定义匹配的含义。最简单和最严格的匹配是简单的字符串相等。更柔和的匹配将容忍大小写差异。更柔和的仍然是对名字/姓氏倒置的容忍度。 (显示在 sn-p 中)。

最柔和的匹配是允许名称中的微小差异(重新排序不会通过 levenshtein 检查记录为微小差异),除非我们比较各个标记之间的距离。

const names = ['Alan Hope', 'Greg Day', 'Alan Peters']

function softMatch(nameA, nameB) {
  if (nameA === nameB) return true;  

  const reverse = name => name.split(' ').reverse().join(' ')
  
  const lcA = nameA.toLowerCase();
  const lcB = nameB.toLowerCase();
  
  if (lcA === lcB) return true; // case insensitive
  if (reverse(lcA) === lcB) return true;  // order and case insensitive
  return false
}

let matches = names.filter(name => softMatch(name, 'peters Alan'))
console.log(matches)

matches = names.filter(name => softMatch(name, 'No Match'))
console.log(matches)

如果名称有两个以上的子名称,并且任何排序都是匹配的,那么匹配可以如下实现...

const names = ['Alan Randolph Hope', 'Greg Herbert Walker Day', 'Alan Jefferson Peters']

function softMatch(nameA, nameB) {
  let subnamesA = nameA.split(' ').map(n => n.toLowerCase())
  let subnamesB = nameB.split(' ').map(n => n.toLowerCase())
  
  // sort lexically and compare
  subnamesA = subnamesA.sort();
  subnamesB = subnamesB.sort();

  return subnamesA.every(function(element, index) {
    return element === subnamesB[index]; 
  });
}

let matches = names.filter(name => softMatch(name, 'peters Alan jefferson'))
console.log(matches)

matches = names.filter(name => softMatch(name, 'No Match'))
console.log(matches)

【讨论】:

  • 我附上了一张来自 Youtube 视频的类似解决方案的图片。这可能类似于解决方案还是您的建议是唯一的方法?
  • 我的建议和您发布的图片在某种意义上是一致的,即使用定义匹配含义的谓词过滤列表。 youtube 图像似乎将子名称表示为一个数组,并且对于 N 个名称的任何排序都为真。我将进行编辑以澄清。
  • @LiamMcCormick - 已编辑。在您的应用程序中,要匹配的名称列表可能是一个列数组,因此不需要拆分。只需转换为小写并排序。 (排序,IMO,使代码比每个/一些更具可读性)
【解决方案2】:

替代方案:

即使搜索输入颠倒或姓/名缩写(例如 Alan H. 或 Al Hope

,您也可以尝试以下示例实现来查找匹配的名称em>) 以获得更灵活的搜索方法:
const studentNames = ['Alan Randolph Hope', 'Greg Herbert Walker Day', 'Alan Jefferson Peters']

function findMatch(){
 var match = run("Hope Al"); 
 console.log(match);
 console.log(match.length>0);
}

function run(searchString) {
  var res = [];
  let findDuplicates = arr => arr.filter((item, index) => arr.indexOf(item) != index);
  var searches = searchString.split(" ");
  searches.forEach(search=>{
    studentNames.forEach(name =>{
      if(name.toLowerCase().includes(search.toLowerCase())){
        res.push(name);
      }        
    });
  });
  return [...new Set(findDuplicates(res))];
}

示例演示:

  • 搜索词是Hope Al:

  • 搜索词是Greg D:

参考:

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-12-21
    • 2016-06-16
    • 2016-12-02
    • 2013-05-24
    • 1970-01-01
    相关资源
    最近更新 更多