2
\$\begingroup\$

I have a search-function, that searches for specific data within a huge Object.

Depending on how good a found entry matches, the finding gets "matchPoints" (or "Priority")

var findings = {};
for(var element in hugeObject){
    var points = getMatchPoints( inputToSearchFor, hugeObject[element] );
    if( points !== 0 ){    //It matched. At least a bit.
        findings[ points ] = element;
    }
}

Now I have all Elements, that somehow matched, within findings.

The function which implements this has to return an Array of all these elements. The most relevant result on the first place.

I currently use this for sorting:

var priorities = Object.keys(findings);    //Get the matchpoints of all findings
priorities.reverse(); //Sort with reverse order (highest priority / most matchpoints first)

var result = [];
for(var i=0; i<priorities.length; i++){
    result.push( findings[i] );
}
return result;

I have several issues with this code:

  • It is inefficient and probably very slow
  • The .reverse() function sorts the priorities alphabetically, not numerically
  • If 2 findings have the same amount of matchpoints, the findings-entry gets overwritten. So the result isn't even valid.

How can I solve this problem in an efficient and elegant way?

Edit: I should mention, that although the object where I search is very big, I only get few valid results which matchPoints > 0. In fact, most of the time I'll get only 2-3 matches at all.

\$\endgroup\$

1 Answer 1

2
\$\begingroup\$

The .reverse() function sorts the priorities alphabetically, not numerically

This is because Object.keys returns an array of strings.

If 2 findings have the same amount of matchpoints, the findings-entry gets overwritten. So the result isn't even valid.

Right, you want to push matches onto the array and sort it afterwards.

var findings = [];
for (var element in hugeObject) {
    var points = getMatchPoints(inputToSearchFor, hugeObject[element]);
    if (points) {
        // It matched. At least a bit.
        findings.push({ points: points, element: element });
    }
}
findings.sort(function(a, b) { return b.points - a.points; });

Here I'm creating a new object with the number of match points stored in points and the found object stored in element, but you could store the point count directly in the found object if it makes more sense.

\$\endgroup\$
6
  • \$\begingroup\$ That's a much better approach than mine :) (Can you correct the findings-initialisation in your answer to =[];?) \$\endgroup\$
    – maja
    Commented Jun 20, 2014 at 20:13
  • \$\begingroup\$ Why is it neccessary to use return a.points - b.points;? Wouldn't return a.points > b.points; also work? \$\endgroup\$
    – maja
    Commented Jun 20, 2014 at 20:16
  • \$\begingroup\$ Opps, fixed initialization. Array.prototype.sort is really looking for a positive or negative number (or zero) to be returned, so the boolean resulting from a.points > b.points has to be converted to a number, and it would never be negative. I think it's more correct and efficient to do it this way. \$\endgroup\$
    – Dagg
    Commented Jun 20, 2014 at 20:22
  • \$\begingroup\$ I just noticed you are sorting in descending order, so you really want b.points - a.points \$\endgroup\$
    – Dagg
    Commented Jun 20, 2014 at 20:26
  • \$\begingroup\$ If I put the points-property directly into the element-field: Is there a convinient way of removing this property in the findings-array afterwards? If not, I would have to use a for loop. \$\endgroup\$
    – maja
    Commented Jun 20, 2014 at 20:30

Your Answer

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

Not the answer you're looking for? Browse other questions tagged or ask your own question.