patternjavascriptMinor
My attempt at a weighted search in JavaScript
Viewed 0 times
javascriptweightedsearchattempt
Problem
I tried to make a weighted search function in JavaScript. I've been improving my JS lately but still not sure about some best practices, wondering if there's any improvements I could make, or if I've ended up doing it completely wrong.
The intention is to keep it quite flexible so it can take an array of filter functions, each with its own weight, it also takes a property on which to sort items with equal weights.
The search function is
A weighted test is an object of the form:
And would be used in a manner such as:
This would return an array where either the title or description contain "test" and ordered by:
The intention is to keep it quite flexible so it can take an array of filter functions, each with its own weight, it also takes a property on which to sort items with equal weights.
The search function is
function weightedSearch(array, weightedTests, sortProperty) {
return array.map(function (e) {
return {
element: e, weight: weightedTests.map(function (weightedTest) {
var testResult = weightedTest.test(e);
return testResult * weightedTest.weight;
}).reduce(function (previousValue, currentValue) { return previousValue + currentValue; }, 0)
};
}).filter(function (element) {
return element.weight > 0;
}).sort(function (obj1, obj2) {
//sort first by weight
if (obj1.weight > obj2.weight) {
return -1;
} else if (obj1.weight obj2.element[sortProperty]) {
return 1;
} else {
return 0;
}
}).map(function (e) {
return e.element;
});
}A weighted test is an object of the form:
{test: function(element){}, weight: relativeWeightOfTheTest}And would be used in a manner such as:
var search = "test";
var results = weightedSearch(arrayToSearch, [
{ test: function (testElement) { return testElement.title.toLowerCase().indexOf(search) >= 0; }, weight: 2 },
{ test: function (testElement) { return testElement.description.toLowerCase().indexOf(search) >= 0; }, weight: 0.5 }
], "title")This would return an array where either the title or description contain "test" and ordered by:
- Appearing in title and description
- Appearing in title
Solution
I like it, from a once over:
-
I would change around the first block, there is too much happening horizontally:
-
The sorting by weight I would do like this:
-
The last
-
Other than that the code runs fine on JsHint, is well commented and easy to follow.
map,filter,reduceetc. are not the most efficient functions, they make for readable code, not for speedy sorting/searching. See this : http://jsperf.com/arraymap, a simplyforloop beats everything else every time, this also goes forfilter,reduceetc.
-
I would change around the first block, there is too much happening horizontally:
return array.map(function (e) {
return {
element: e,
weight: weightedTests.map(function (weightedTest) {
return weightedTest.test(e) * weightedTest.weight;
}).reduce(function (previousValue, currentValue) {
return previousValue + currentValue; }, 0)
};
})-
The sorting by weight I would do like this:
//sort first by weight if possible
var weightDifference = obj2.weight- obj1.weight;
if (weightDifference) {
return weightDifference;
}-
The last
return 0 does not need to be in an else block-
Other than that the code runs fine on JsHint, is well commented and easy to follow.
Code Snippets
return array.map(function (e) {
return {
element: e,
weight: weightedTests.map(function (weightedTest) {
return weightedTest.test(e) * weightedTest.weight;
}).reduce(function (previousValue, currentValue) {
return previousValue + currentValue; }, 0)
};
})//sort first by weight if possible
var weightDifference = obj2.weight- obj1.weight;
if (weightDifference) {
return weightDifference;
}Context
StackExchange Code Review Q#43500, answer score: 4
Revisions (0)
No revisions yet.