Moode Forum

Full Version: Revised library sorting
You're currently viewing a stripped down version of our content. View the full version with proper formatting.
I have an idea to revise the library sorting so that it is case insensitive and also places names and words outside the normal English character set where I expect them to land. I put this together because I didn't like certain artists and albums landing at the bottom because of case or a single letter with a diacritic on it.

This is definitely more expensive than the current sorting code, and probably needs more testing, but its running on my copy of Moode and seems to work well and be acceptably fast on a raspberry pi touch screen. Using the localeCompare method exclusively was noticeably slow on a pi.


Code:
/* Sorting method update for playerlib.js. Replaces the following code:

       // sort the lists
       allGenres.sort();
        allArtists.sort(function(a, b) {return removeArticles(a) > removeArticles(b) ? 1 : -1;});
       allAlbumsTmp.sort(function(a, b) {return removeArticles(a['album']) > removeArticles(b['album']) ? 1 : -1;});
       
With the new code below*/

       // Test Sort rewrite: case insensitive and uses locale (set manually here to US English)
       // Reasons: Default sort places 'The xx' below 'Yes' because xx is lower case. Additionally,
       //          default sort places non-ascii characters at the bottom, so Ólafur Arnalds sorts
       //          to the end of the artists list, and Ágætis Byrjun sorts to the end of the Albums
       //          list, which doesn't match expectations.
       //
       // Using the localeCompare method to sort the entire list solves both issues, but it is slow
       //
       // Instead we use a hybrid approach, which checks first for non-latin characters. If
       // the string is basic, we convert to lower case and then sort. If the string
       // contains other characters, then we use localeCompare to sort
       //
       // Note: this appears to add a lot of code, but seems to work fairly well and is
       // acceptably fast on a library of 6664 tracks. Certainly needs more testing.
       //
       // This may only be suitable for mostly-latin languages like English
       
       // Sort the filter lists (Genre, Artist, Albums)
       var sortLocale = 'en-US';       // This really shouldn't be hard-coded
       var noLocale = /^[\w-.\s,]*$/; // Regex to test for basic latin characters only
       allGenres.sort(function(a, b) {
           if (noLocale.test(a) && noLocale.test(b)) {
               return (a.toLowerCase() > b.toLowerCase() ? 1 : (a.toLowerCase() == b.toLowerCase() ? 0 : -1));
           } else {
               return a.localeCompare(b, sortLocale);
           }
       });
       allArtists.sort(function(a, b) {
           if (noLocale.test(a) && noLocale.test(b)) {
               return (removeArticles(a).toLowerCase() > removeArticles(b).toLowerCase() ? 1 : (removeArticles(a).toLowerCase() == removeArticles(b).toLowerCase() ? 0 : -1));
           } else {
               return removeArticles(a).localeCompare(removeArticles(b), sortLocale);
           }
       });
       allAlbumsTmp.sort(function(a, b) {
           if (noLocale.test(a['album']) && noLocale.test(b['album'])) {
               return (removeArticles(a['album']).toLowerCase() > removeArticles(b['album']).toLowerCase() ? 1 : (removeArticles(a['album']).toLowerCase() == removeArticles(b['album']).toLowerCase() ? 0 : -1));
           } else {
               return removeArticles(a['album']).localeCompare(removeArticles(b['album']), sortLocale);
           }
       });
Hi,

Nice idea :-)

Below is the sort routine for upcoming 4.3 release. It uses Intl.Collator() and collator.compare(a, b) instead of localeCompare() which is super slow. Its in a try/catch block to cover Browsers/Javascript that may not support collator, and its case insensitive (sensitivity: 'base').

Give it a try. It should be fast :-)

Code:
        // sort the lists
        allGenres.sort();
        // sort using natural ordering
        try {
            var collator = new Intl.Collator(undefined, {numeric: true, sensitivity: 'base'});
            allArtists.sort(function(a, b) {
                a = removeArticles(a);
                b = removeArticles(b);
                return collator.compare(a, b);
            });
            allAlbumsTmp.sort(function(a, b) {
                a = removeArticles(a['album']);
                b = removeArticles(b['album']);
                return collator.compare(a, b);
            });
        }            
        // fallback to default ordering
        catch (e) {
            allArtists.sort(function(a, b) {
                a = removeArticles(a.toLowerCase());
                b = removeArticles(b.toLowerCase());
                return a > b ? 1 : (a < b ? -1 : 0);
            });
            allAlbumsTmp.sort(function(a, b) {
                a = removeArticles(a['album'].toLowerCase());
                b = removeArticles(b['album'].toLowerCase());
                return a > b ? 1 : (a < b ? -1 : 0);
            });
        }
Thanks, Tim, I'll try it out on my local copy.
Tim, I tested your code and it appears to work great. No formal benchmarks, but it appears sufficiently fast. I appreciate you posting your approach before 4.3 is ready.
The feedback is very helpful so thanks for testing :-)