Reputation: 569
I'm banging my head against the wall trying to work this out... Basically, I have an object with a structure similar to this:
results = {
1 : {
url : '/',
matches: {
title : true,
h1 : false,
copy : 2
}
},
2 : {
url : '/?id=2',
matches: {
title : true,
h1 : true,
copy : 0
}
},
3 : {
url : '/id=3',
matches: {
title : false,
h1 : false,
copy : 6
}
}
}
This is a result set from a custom search. I need the results to have weight for relevancy based on the matches within the objects. The results should be sorted like this:
Results having matches.title == true are the topmost results. Within this subset, matches.h1 being true carries the most weight (topmost), followed by the number of occurrences within the page copy (matches.copy).
Results having matches.h1 == true are to display next in the results view, sorted by the number of occurrences within the page copy (matches.copy).
Results with matches.title and matches.h1 both being false are sorted on matches.copy, in descending order.
Is this doable with the current object structure? Or do I need to split it up and cross-reference each subset? Gah! It's so early, and the coffee isn't working :(
EDIT: Converted result set to an array of objects. New structure:
results = [
{ pageid: 1, url: '/', matches: { title: true, h1: false, copy: 2 } },
{ pageid: 2, url: '/?id=2', matches: { title: true, h1: true, copy: 0 } },
{ pageid: 3, url: '/?id=3', matches: { title: false, h1: false, copy: 6 } }
]
The sorting is still escaping me. I've done simple sorts before, but nothing to this degree. I came across LINQ, which seems promising, but I have no experience using it. Not sure if that's the right direction or not.
Upvotes: 1
Views: 638
Reputation: 154918
I recommend using an array instead, which is designed for an ordered list.
You can use .sort
and provide a custom search function: http://jsfiddle.net/uR4Jn/2/.
First try to move up an element having .title === true
if the other element has .title === false
. Otherwise, try to move up an element having .h1 === true
if the other element has .h1 === false
. Lastly, just sort on .copy
. (And, move the item down in the first two cases if the opposite is true.)
var results = [
{
url : '/',
matches: {
title : true,
h1 : false,
copy : 2
}
},
{
url : '/?id=2',
matches: {
title : true,
h1 : true,
copy : 0
}
},
{
url : '/id=3',
matches: {
title : false,
h1 : false,
copy : 6
}
},
{
url : '/id=3',
matches: {
title : false,
h1 : false,
copy : 7
}
}
];
results = results.sort(function(a, b) {
return (a.matches.title && !b.matches.title ? -1
: (!a.matches.title && b.matches.title ? 1
: (a.matches.h1 && !b.matches.h1 ? -1
: (!a.matches.h1 && b.matches.h1 ? 1
: b.matches.copy - a.matches.copy))));
});
Upvotes: 5
Reputation: 318638
It's easily possible by calling results.sort(function(a, b) { ... });
and then adding the proper logic to the callback: Return -1 if a<b, 1 if a>b, 0 if a==b.
Objects in JavaScript are not ordered. You need to convert it to an array if you want a specific order:
var resultList = [];
for(var elem in results) {
resultList.push(results[elem]);
}
resultList.sort(function(a, b) {
// perform your sorting
});
Since objects are passed by reference, you can still use results[..]
to access one of the objects.
Upvotes: 1