比较数组JavaScript时查找最接近的匹配项

时间:2019-02-25 18:57:08

标签: javascript arrays

假设我有一个对象数组foo,每个对象都有一个属性bar,它是一个数组。

foo[0].bar = [1]
foo[1].bar = [2]
foo[2].bar = [2,4,5]
foo[3].bar = [2,4,6]
foo[4].bar = [2,4,6,7]
foo[5].bar = [2,4,6,9]
foo[6].bar = [3]

我需要一种方法来测试阵列并像这样进行特定的“最佳匹配”搜索:

mySearch([2,4,6]);     // returns [foo[3], foo[4], foo[5]]
mySearch([2,4,6,7]);   // returns [foo[4]]
mySearch([2,4,6,8]);   // returns [foo[3]]
mySearch([3,2,1]);     // returns [foo[6]]
mySearch([4]);         // returns []

本质上,我希望foo[]中的对象与测试数组中的尽可能多的精确数字匹配。顺序很重要,但是测试数组或目标对象的长度都是可变的。

我也许可以使用少量的for-next循环和if-thens来解决这个问题,但是我觉得应该有一个更好的方法。 (如果有帮助,我可以提供一个常量maxLength,它等于集合中最长数组的长度。)

谢谢!

编辑:对不起,我在期望结果中的变量与上次编辑时有些混淆。

编辑2:对不起,我在描述这一点时非常困难。我正在处理的情况类似于阅读:给定标准英语词典中的字符串"HELLOWORL",我想要一个能找到适合的最长单词的函数:"HELLO"(跳过{{1 }}和"HE"也在字典中)。

4 个答案:

答案 0 :(得分:1)

这是尝试,虽然不确定这是您追求的。

const foo = [{bar: [1]}, {bar: [2]}, {bar: [2,4,5]}, {bar: [2,4,6]}, {bar: [2,4,6,7]}, {bar: [2,4,6,9]}, {bar: [3]}];


    function search(arr, minLengthMatch){
       if (!minLengthMatch) // specify min match or use the default the arr length
            minLengthMatch = arr.length;
     return foo.filter(function(x){
            var matchFound = 0;
            for(var i in arr){
              if (x.bar.indexOf(arr[i]) == i)
                   matchFound++;
              else break; // tha match seq have been broken
            }
            return matchFound>=minLengthMatch
       });
       // change from .map to flatMap if you want a single array
    }

    console.log(search([2,4,6]));

答案 1 :(得分:1)

您可以使用fooJSON.stringify数组的相同长度切片与输入数组进行比较(假设数组值很简单,就像示例中的整数一样)。然后,您需要根据何时匹配精确长度,更长和更短长度数组的规则,对foo的适当子集进行迭代。

请参见下面的代码段

const matchBars = (objs, arr) => {

  let matches = objs.reduce((acc, obj) => {
    let len = arr.length <= obj.bar.length ? arr.length : obj.bar.length;
    let a = JSON.stringify(arr.slice(0, len));
    let b = JSON.stringify(obj.bar.slice(0, len));
    if (a === b) {
      if (len < arr.length) {
        acc.short.push(obj);
      } else {
        acc.long.push(obj);
      }
    }
    return acc;
  }, {long: [], short: []});
  
  if (!matches.long.length) {
    return matches.short.sort((a, b) => b.bar.length - a.bar.length).slice(0, 1);
  }
  
  return matches.long;
  
}

const foo = [{bar: [1]}, {bar: [2]}, {bar: [2,4,5]}, {bar: [2,4,6]}, {bar: [2,4,6,7]}, {bar: [2,4,6,9]}, {bar: [3]}];
console.log(matchBars(foo, [2, 4, 6]));
// [{bar: [2,4,6]}, {bar: [2,4,6,7]}, {bar: [2,4,6,9]}]
console.log(matchBars(foo, [2, 4, 6, 8]));
// [{bar: [2,4,6]}]

答案 2 :(得分:1)

我不认为有一种非常简单的方法可以做到这一点,但就我所知,这将达到目的

const foo = [{bar: [1]}, {bar: [2]}, {bar: [2,4,5]}, {bar: [2,4,6]}, {bar: [2,4,6,7]}, {bar: [2,4,6,9]}, {bar: [3]}, {bar: [3, 4]}];

const mySearch = searchArray => {
  var maxMatch = 0;
  const searchString = searchArray.join("")
  const matchingObjectsArray =  foo.map(obj => {
    const barString = obj.bar.join("")         
    if (barString.startsWith(searchString) 
       || searchString.startsWith(barString)){
       
        maxMatch = searchString.length >= barString.length ?
                    barString.length : 
                    searchString.length

       return obj
     }else return null //if there are no matches replace obj with null
   }).filter(Boolean) // get rid of nulls
  const filteredMatches = matchingObjectsArray
                          .filter(obj => obj.bar.length >= maxMatch)
                              
  return filteredMatches
}
console.log(mySearch([3,4,6,9])) /* { bar: [ 3, 4 ] } ] */

答案 3 :(得分:1)

  

注意::该答案的较早版本在Javascript中滥用了foreach。此答案已被修改以解决此问题

我想我现在就知道了。

这是一个只有2个循环和2个ifs的解决方案:

  

注意::此解决方案假定foo是全局变量。传递foo或将mySearch()改为foo的成员函数可能是一个好主意,但希望这足以为您提供图片。

mySearch(test) {
    var result[]; // the list of matches
    var maxLen = 0; // to be filled later
    // loop control vars.
    var j=0;
    var i=0;
    // loop 1, for searching every bar
    for(j=0;j<foo.length;j++) {
        // if 1, for knowing our max length. 
        // Could be replaced with a ?:, but I don't remember if those exist in js
        // if they do, it'd look something like
        // maxLen = foo[j].bar.length > test.length ? test.length : foo[j].bar.length;
        if(foo[j].bar.length > test.length) {
            maxLen = test.length;
        } else {
            maxLen = foo[j].bar.length;
        }

        // a flag to hold if our current bar matches
        var doesMatch = true;

        // loop 2. This one is because we have a variable amount of
        for(i =0; i<maxLen;i++) {
            doesMatch = doesMatch && (foo[j].bar[i] == test[i]); 
        }

        // if 2, see what we matched
        if(doesMatch) {
            // if we did, add it to the results
            result.push(foo[j]);
        }
    }
    // return what matched
    return result;
}

希望这对于您正在寻找的东西足够有效。

P.S。使用?:语法,您可以将行maxLen = myFoo.bar.length > test.length ? test.length : foo[j].bar.length;更改为 var maxLen = foo[j].bar.length > test.length ? test.length : foo[j].bar.length;,因为maxLen仅在循环中使用。

P.P.S。您还提到您已经有一个maxLength可用,因此如果它的用途与我的maxLen相同,那么您可以使用它。