Came up with the following function to perform an array sort, making use of closures to define the callback function that will be used by usort(). Trying to decide if it's a decent way to accomplish this, or if there might be a cleaner way?
Please give us a simple answer, so that we don't have to think, because if we think, we might find answers that don't fit the way we want the world to be." ~ from Nation, by Terry Pratchett
"But the main reason that any programmer learning any new language thinks the new language is SO much better than the old one is because he’s a better programmer now!" ~ http://www.oreillynet.com/ruby/blog/...ck_to_p_1.html
I like it. My first thought was to declare all of the closures (allowing you to use the 'newtoold' closure inside your 'mosthelpful'/'leasthelpful' closures), and do away with the switch statement:
PHP Code:
function applySort_revised( array $data,$orderBy='newtoold' ){
Likes and dislikes would be simple integer values (how many users liked or disliked that review), and for those with the same number, they should then be sorted new-to-old. (And if any of that logic bothers you, that's not negotiable. )
Last edited by NogDog; 11-13-2012 at 05:03 PM.
Please give us a simple answer, so that we don't have to think, because if we think, we might find answers that don't fit the way we want the world to be." ~ from Nation, by Terry Pratchett
"But the main reason that any programmer learning any new language thinks the new language is SO much better than the old one is because he’s a better programmer now!" ~ http://www.oreillynet.com/ruby/blog/...ck_to_p_1.html
PS: I do like the the idea of new-to-old being defined once and used as needed. Hmm....
Please give us a simple answer, so that we don't have to think, because if we think, we might find answers that don't fit the way we want the world to be." ~ from Nation, by Terry Pratchett
"But the main reason that any programmer learning any new language thinks the new language is SO much better than the old one is because he’s a better programmer now!" ~ http://www.oreillynet.com/ruby/blog/...ck_to_p_1.html
Heh...stupid copy-and-paste errors...now I have to send myself email to check tomorrow whether that bug is still in the actual code (applying strtotime() to the likes/dislikes). Thanks for catching that (hasn't gone to QA yet).
Please give us a simple answer, so that we don't have to think, because if we think, we might find answers that don't fit the way we want the world to be." ~ from Nation, by Terry Pratchett
"But the main reason that any programmer learning any new language thinks the new language is SO much better than the old one is because he’s a better programmer now!" ~ http://www.oreillynet.com/ruby/blog/...ck_to_p_1.html
Likes and dislikes would be simple integer values (how many users liked or disliked that review), and for those with the same number, they should then be sorted new-to-old. (And if any of that logic bothers you, that's not negotiable. )
Doesn't bother me per se (and I certainly understand if it's simply "non negotiable"), but have you considered using "dislikes" to break a "likes" tie (and vice-versa)? e.g.,
PHP Code:
## untested ##
$mosthelpful = function( $a,$b )use( $leasthelpful,$newtoold ){
$diff = $b['likes'] - $a['likes'];
if( $diff == 0 ){ // tied for likes
// negate result: we want the *least* disliked, not the *most* disliked
$diff = -( $leasthelpful( $a,$b ) );
}
if( $diff == 0 ){ // tied for dislikes also
$diff = $newtoold( $a,$b );
}
return $diff;
};
I've actually considered looking at different formulas for figuring out some sort of total "likeability" rating taking both counts into consideration, with weighting factors based on total number of responses and so forth, but the powers that be want to keep it simple (for now). Obviously it's not exactly perfect right now, since one review could, in theory, show up at the top of both the most helpful and least helpful sorts, which at least seems illogical at first glance (and second glance?).
Oh, and if anybody is wondering why I'm not sorting it in the DB query, it's because part of the review data comes from a DB query and the other part comes from a separate API call to another data source, and for now this is the easiest way to get the two data sets merged and sorted (subject to change without notice ).
Please give us a simple answer, so that we don't have to think, because if we think, we might find answers that don't fit the way we want the world to be." ~ from Nation, by Terry Pratchett
"But the main reason that any programmer learning any new language thinks the new language is SO much better than the old one is because he’s a better programmer now!" ~ http://www.oreillynet.com/ruby/blog/...ck_to_p_1.html
I'm late here, but I'm stepping in to say I like it. I know there are lots of people who want OO with everything, but in cases like this a functional approach is much cleaner than a whole class and a bunch of instances all for the sake of implementing one method.
One idea that comes to me when I see this is the idea of having the caller function provide the sort criterion function, rather than have applySort construct it. Then the criterion can make use of additional values drawn from the scope of the caller. (You can still have a lookup of really common criteria, and have applySort look to see if it was passed a callable thing or the name of something in the lookup table.) You could also refactor the common parts of those functions into a more generic version.
PHP Code:
function sortByField($field) { // Determine appropriate comparison function to use for this type of field // (strnatcasecmp() might be enough depending on the format used for timestamps)
// Or have a distinct lookup function that maintains an array of fieldname => comparator pairs.
Thanks for the feedback, guys. This sort of discussion is always a lot more "fun" than, say, "Why do I get this 'not a resource' error?"
Unfortunately (or fortunately), after what I'd cobbled together in a day-and-a-half for what was supposedly an urgent requirement has suddenly turned into an "Oops, sorry for the miscommunication, but we don't want/need that feature." So now I have to pull it out of the main git branch for that project and stick it away in its own branch for if/when it becomes a requirement again -- at which point we'll probably decide to do it in a completely different way.
Please give us a simple answer, so that we don't have to think, because if we think, we might find answers that don't fit the way we want the world to be." ~ from Nation, by Terry Pratchett
"But the main reason that any programmer learning any new language thinks the new language is SO much better than the old one is because he’s a better programmer now!" ~ http://www.oreillynet.com/ruby/blog/...ck_to_p_1.html
that got me thinking. in terms of performance, the best approach is to declare the closure outside of the function, and pass it in as a argument (or use via global), rather than declaring it each time inside the function:
In this particular use case, it would only get defined once on any given page request, but from a scalability issue it's definitely worth thinking about. I suppose the OOP alternative might be to use a decorator pattern, though the framework we're using makes that a bit clunkier than I'd like. Hmm...now I'm thinking as I type (a dangerous thing): we have a sort of Registry-like class in which I could create/store the selected closure-style sort function, create an interceptor class for that particular action that would populate the registry with the applicable closure based on the url criteria, then use that in the method where I have to do the sort....
Now I have to send myself another email -- just in case this rises from the grave at some point.
Please give us a simple answer, so that we don't have to think, because if we think, we might find answers that don't fit the way we want the world to be." ~ from Nation, by Terry Pratchett
"But the main reason that any programmer learning any new language thinks the new language is SO much better than the old one is because he’s a better programmer now!" ~ http://www.oreillynet.com/ruby/blog/...ck_to_p_1.html
Last night I kept getting parse errors and/or it always redefined the closure. But I was really tired.
...static (or possibly is_callable()) seems to kill performance, not help it. 1,000 iterations (same test as before) took .01s; it's better to just define the closure each time!
Bookmarks