0

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>

Above is the structure of my project.

I need to return the most relevant result when comparing string and entry arrays.

Array.prototype.every() Is the closest I've got in achieving my goal after countless hours trial and error of trying...

The problem is shown in output #3. I understand Array.prototype.every() will return false if the element to find is not present in the array but there must be a workaround.

If I remove non similar elements on both arrays, I thought it would solve the problem.

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

I try to use xyz as the new array for strings but then the element in entry array will still be present, thus will return false.

I can get the difference on both arrays...

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

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

...but then I'm stuck in trying to find the suitable condition to apply.

Hope I explained it well and thanks for your help..

1 Answer 1

1

You could use a filter to find all items that contain each string, keeping track of the count and the position of those that do to find the first one that has the most matches.

Something like:

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

** UPDATE: to return multiple group names where matches have been found, ordered by match count then by group numbers **

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'));

Sign up to request clarification or add additional context in comments.

24 Comments

Thanks sir! I'm testing it in my project and it's flawless so far :)
np. Just out of curiosity though, is there a reason for just wanting to get the first array with the most matches? All the ones I've done and seen like this would have wanted to get both the "two" and "three" results.
I actually just wanted to display the array with the most relevant match.. then return random item from the group where it found the match. And you solved my problem :) thanks again!
OK, np. I've actually just updated the code, though. The "splice(1)" function actually removes part of an array, so it is gone for good. I've changed that part to create an simple array using just the contents of it instead - [entryArr[pos][1]]
nope, ur first code is fine. we use slice(1) so it wont return the first items on each group. We only need that part to store keywords.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.