allocen allocen - 2 months ago 8
Javascript Question

Javascript custom sorting issue in array

i got some sort of an issue with my custom sorting. So, basically i have this array:

[ 'src/app/account/account.js',
'src/app/account/dashboard/characters/characters.js',
'src/app/account/dashboard/characters/detail/detail.js',
'src/app/account/dashboard/dashboard.ctrl.js',
'src/app/account/dashboard/dashboard.js',
'src/app/account/dashboard/panels/admin.ctrl.js',
'src/app/account/dashboard/panels/users.ctrl.js',
'src/app/account/donate/donate.ctrl.js',
'src/app/account/donate/donate.js',
'src/app/account/settings/settings.ctrl.js',
'src/app/account/settings/settings.js',
'src/app/account/vote/vote.ctrl.js',
'src/app/account/vote/vote.js',
'src/app/membership/dialogs/login.ctrl.js',
'src/app/membership/dialogs/register.ctrl.js',
'src/app/membership/dialogs/termsOfService.ctrl.js',
'src/app/membership/membership.ctrl.js',
'src/app/membership/membership.module.js',
'src/app/news/news.ctrl.js',
'src/app/news/news.js',
'src/app/noctis.ctrl.js',
'src/app/noctis.js',
'src/app/widgets/playersOnline/playersOnline.js',
'src/app/widgets/rankings/rankings.js',
'src/app/widgets/serverDetails/serverDetails.js',
'src/common/directives/feeds/feeds.js',
'src/common/directives/panel/panel.js' ]


And what i would like that after the src/app/ the very first js that comes after the very first folder after src/app/ in our case: account, membership(can be more custom names) to be loaded first, like in the next example:

['src/app/membership/membership.module.js',
'src/app/membership/membership.ctrl.js',
'src/app/membership/dialogs/login.ctrl.js',
'src/app/membership/dialogs/register.ctrl.js',
'src/app/membership/dialogs/termsOfService.ctrl.js',]


Can you guys help me with some code for my needs? src/app will always be a fixed name except of the next directory that comes after src/app/.

Basically what comes after the unknown name of the directory after src/app, the sub directories in our case(dialogs) or can be something else like(detail, detail/character), to be loaded latest no matter what.

Basically this is the whole function:

function sortJSFiles(files) {
var src = [];
var vendor = [];
files.forEach(function(item) {
if (item.startsWith('src')) {
src.push(item);
} else {
vendor.push(item);
}
});

src.sort(function(a, b) {
var replace = ['noctis.js', 'noctis.ctrl.js', '.module.js', '.ctrl.js'];

function replaceCB(previousValue, currentValue, currentIndex, array) {
return previousValue.replace(currentValue, currentIndex);
}
return replace.reduce(replaceCB, a).localeCompare(replace.reduce(replaceCB, b));
});
return vendor.concat(src);
}


What it does, is that in paramater files comes a lot of paths with js files and i'm trying to sort them after my rule. The problem is, for example taking membership example:

['src/app/membership/dialogs/login.ctrl.js',
'src/app/membership/dialogs/register.ctrl.js',
'src/app/membership/dialogs/termsOfService.ctrl.js',
'src/app/membership/membership.module.js',
'src/app/membership/membership.ctrl.js']


It succesffully change the sort like loading *.js files that starts first with .module.js and than with .ctrl.js but there is a problem in my code that i need that any js file that comes after src/app/somefolder to be loaded first and any subfolders that are in that somefolder to be loaded latest no matter what.

Answer

I am not sure I understood you correctly (it would have been nice if you would have added the literal expected output for your sample data).

I think you want to have the folders sorted, but within the same folder, you want the files in there to be sorted before any of the subfolders in that same folder. And this should be true at every nested level.

To get the files sorted first in every folder, you should in fact extract the folders only, and sort those, and only when two items have exactly the same folder sequence, sort by the file name.

This you can do as follows:

src = src.map(function (path) {
    var i = path.lastIndexOf('/');
    return [path.substr(0, i), path.substr(i)];
}).sort(function (a, b) {
    var i = +(a[0] == b[0]);
    return  a[i].localeCompare(b[i]);
}).map(function (pair) {
    return pair[0] + pair[1];
});

var src = [ 'src/app/account/account.js',
  'src/app/account/dashboard/characters/characters.js',
  'src/app/account/dashboard/characters/detail/detail.js',
  'src/app/account/dashboard/dashboard.ctrl.js',
  'src/app/account/dashboard/dashboard.js',
  'src/app/account/dashboard/panels/admin.ctrl.js',
  'src/app/account/dashboard/panels/users.ctrl.js',
  'src/app/account/donate/donate.ctrl.js',
  'src/app/account/donate/donate.js',
  'src/app/account/settings/settings.ctrl.js',
  'src/app/account/settings/settings.js',
  'src/app/account/vote/vote.ctrl.js',
  'src/app/account/vote/vote.js',
  'src/app/membership/dialogs/login.ctrl.js',
  'src/app/membership/dialogs/register.ctrl.js',
  'src/app/membership/dialogs/termsOfService.ctrl.js',
  'src/app/membership/membership.ctrl.js',
  'src/app/membership/membership.module.js',
  'src/app/news/news.ctrl.js',
  'src/app/news/news.js',
  'src/app/noctis.ctrl.js',
  'src/app/noctis.js',
  'src/app/widgets/playersOnline/playersOnline.js',
  'src/app/widgets/rankings/rankings.js',
  'src/app/widgets/serverDetails/serverDetails.js',
  'src/common/directives/feeds/feeds.js',
  'src/common/directives/panel/panel.js' ];

src = src.map(function (path) {
    var i = path.lastIndexOf('/');
    return [path.substr(0, i), path.substr(i)];
}).sort(function (a, b) {
    var i = +(a[0] == b[0]);
    return  a[i].localeCompare(b[i]);
}).map(function (pair) {
    return pair[0] + pair[1];
});

console.log(src);

Explanation of the sort callback function

The sort callback function will receive argument a and b. Each of them is a pair including a path at index 0, and a filename at index 1.

The callback uses a variable i that is intended to get the value 0 or 1. If the paths of a and b are the same, then i will be 1, else it will be 0. It determines whether a comparison is needed on the paths or on the filenames.

The unitary + is used to convert the boolean expression a[0] == b[0] to a number. The conversion is: true=>1, false=>0.