Обходной путь для Array.prototype.every() для сопоставления элементов в массиве

#javascript #jquery #arrays

#javascript #jquery #массивы

Вопрос:

 var groupArray = [
    ['10', 'group one result', 'more result from group1'],
    ['10 20 30', 'group two result', 'another result from group two'],
    ['10 20 40', 'group three result']
];

function compare(entryArr, stringArr) {
    for (var i in entryArr) {
        str = stringArr.split(' '); //to array
        ent = entryArr[i][0].split(' ');  //first items of each group to array

        if (str.every(s => ent.includes(s)))  // compare 
    return entryArr[i].slice(1);
    }
}
//find match from possible strings
console.log(compare(groupArray, '10')) // true
console.log(compare(groupArray, '10 20')) // true
console.log(compare(groupArray, '10 20 60')) // undefined. the result should come from group two  
 <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>  

Выше приведена структура моего проекта.

Мне нужно вернуть наиболее релевантный результат при сравнении массивов строк и записей.

Array.prototype.every() Это самое близкое, что у меня есть для достижения моей цели после бесчисленных часов проб и ошибок…

Проблема показана в выводе # 3. Я понимаю Array.prototype.every() , что вернет false, если элемент, который нужно найти, отсутствует в массиве, но должен быть обходной путь.

Если я удалю не похожие элементы в обоих массивах, я думал, что это решит проблему.

 xyz = str.filter(x => ent.includes(x)) //output: ['10','20'] for sample #3
  

Я пытаюсь использовать xyz в качестве нового массива для строк, но тогда элемент в массиве ввода все равно будет присутствовать, поэтому вернет false .

Я могу получить разницу в обоих массивах…

 entArr = str.filter(x => !ent.includes(x)) // entry array difference

strArr = ent.filter(x => !str.includes(x)) // string array difference
  

… но потом я застрял, пытаясь найти подходящее условие для применения.

Надеюсь, я хорошо объяснил это и спасибо за вашу помощь..

Ответ №1:

Вы могли бы использовать фильтр, чтобы найти все элементы, содержащие каждую строку, отслеживая количество и положение тех, которые делают, чтобы найти первый, который имеет наибольшее количество совпадений.

Что-то вроде:

 var groupArray = [
    ['10', 'group one result'],
    ['10 20 30', 'group two result'],
    ['10 20 40', 'group three result']
];

function compare(entryArr, stringArr) {
  let pos = 0;
  let matches = 0;
    for (var i in entryArr) {
      str = stringArr.split(' ');
      ent = entryArr[i][0].split(' ');
      let f = str.filter(s => ent.includes(s));
      if (f)
        if (f.length > matches) {
          pos = i;
          matches = f.length;
        }
    }
    if (matches > 0) {
      return entryArr[pos].slice(1);
    } else {
      return [];
    }
}
//find match from possible strings
console.log(compare(groupArray, '10')) // returns first entry that matches one value - group one result
console.log(compare(groupArray, '10 20')) // returns first entry that matches both values - group two result
console.log(compare(groupArray, '10 20 60')) // returns first entry with 2 matches - group two result
console.log(compare(groupArray, '50 60 80')) // no matches, returns empty array  

** ОБНОВЛЕНИЕ: для возврата нескольких имен групп, в которых были найдены совпадения, упорядоченных по количеству совпадений, а затем по номерам групп **

 var groupArray = [
    ['10', 'group one result', 'more one result'],
    ['10 20 40', 'group three result'],
    ['10 20 30', 'group two result'],
    ['10 20 30 40', 'group four result'],
    ['20 60', 'group five result']
];

function compare(entryArr, stringArr) {
  // Array to hold ALL matches found
  let matched = [];
  // Loop through the entryArry array
  for (let i = 0; i < entryArr.length; i  ) {
    // split search string into separate values
    str = stringArr.split(' ');
    // split the main array into separate values
    ent = entryArr[i][0].split(' ');
    // find any main array items that contain the search string values
    let f = str.filter(s => ent.includes(s));
    // If found...
    if (f.length > 0) {
      //... push into the matched array
      matched.push([f.length, ...entryArr[i]]);
    }
  }
  // If we have more than one match found, sort the matched array
  // First by match count descending, then by the main array values, ascending
  if (matched.length > 1) {
    matched.sort(function(a, b){
      if (a[0] == b[0]) {
        return a[1] > b[1];
      } else {
        return a[0] < b[0];
      }
    })
    // Now remove the unnecessary parts of each match
    // We only want the group name, not the match count or the group's numbers string
    for (let i = 0; i < matched.length; i  ) {
      matched[i] = matched[i].slice(2);
    }
  }
  // return the result
  return matched;
}

//find match from possible strings
console.log(compare(groupArray, '10'));
console.log(compare(groupArray, '10 20'));
console.log(compare(groupArray, '10 20 60'));
console.log(compare(groupArray, '20 30 40'));  

Комментарии:

1. Спасибо, сэр! Я тестирую его в своем проекте, и пока он безупречен 🙂

2. np. Просто из любопытства, есть ли причина просто хотеть получить первый массив с наибольшим количеством совпадений? Все, что я делал и видел подобным образом, хотели бы получить как «два», так и «три» результата.

3. На самом деле я просто хотел отобразить массив с наиболее подходящим совпадением.. затем верните случайный элемент из группы, в которой он нашел совпадение. И вы решили мою проблему 🙂 еще раз спасибо!

4. ХОРОШО, np. На самом деле я только что обновил код. Функция «splice (1)» фактически удаляет часть массива, поэтому она исчезла навсегда. Я изменил эту часть, чтобы создать простой массив, используя вместо него только его содержимое — [entryArr[pos][1]]

5. нет, ваш первый код в порядке. мы используем slice(1), поэтому он не будет возвращать первые элементы в каждой группе. Нам нужна только эта часть для хранения ключевых слов.