Reputation: 218
Using JavaScript, I have an array of file paths that I'm looping through and checking. If the current item is a folder, I want to bump it to the back of the line and move on to the next item. The end result would be files in front, folders after the last file.
I know this should be easy, but I've been fighting with it for 2 days. I've tried various versions of the following code with no success. For the purpose of this project, I'm assuming it's a folder if there's no period present in the filename.
function sortArray(array) {
console.log('Original array: ' + array);
var z = array.length;
console.log('Array length is ' + z);
for(i = 0; i < z-1; i++)
{
var n = array.indexOf(array[i]);
if (array[i].indexOf('.') === -1)
{
console.log('Item is folder');
var fldr = array.splice(n, 1);
array.push(fldr);
}
}
console.log('Sorted array: ' + array);
}
Upvotes: 1
Views: 213
Reputation: 31
There can be many approaches for this task. If you just want to correct your code then here's the solution:
When you use splice, the whole array to the right of the deleted element is shifted left, and as you are increasing i, the element that comes at the current position is missed. Therefore, you should not increase i in that case.
Another issue: It should be z
in place of z-1
and array.splice(i, 1)
instead of array.splice(n, 1)
function sortArray(array) {
console.log('Original array: ' + array);
var z = array.length;
console.log('Array length is ' + z);
var i = 0;
var sortedCount = 0; // Count of the number of elements already sorted.
for(sortedCount = 0 = 0; sortedCount < z; sortedCount++)
{
var n = array.indexOf(array[i]);
if (array[i].indexOf('.') === -1)
{
console.log('Item is folder');
var fldr = array.splice(i, 1);
array.push(fldr);
}
else i++;
}
console.log('Sorted array: ' + array);
}
Another approach could be to sort the array using sort method with a custom comparison function:
array.sort(function(filePathOne, filePathTwo) {
var oneIsFile = FilePathOne.indexOf('.') == -1 ? 1 : 0;
var twoIsFile = FilePathTwo.indexOf('.') == -1 ? 1 : 0;
return twoIsFile - oneIsFile; // File comes before folder
});
Upvotes: 0
Reputation: 2520
If original order of files and folders matters to you, you could use this function:
function sortFilesAndFolders (originalArray) {
var files = [], folders = [];
originalArray.forEach(function (item) {
if (item.indexOf(".") === -1) {
folders.push(item);
} else {
files.push(item);
}
});
return folders.concat(files);
}
demo: http://jsfiddle.net/4Lnwz4jh/
Upvotes: 0
Reputation: 43728
There are many ways to do this, but here's one using Array.prototype.sort
.
var filesAndFolders = ['file1.txt', 'folder2', 'folder1', 'file2.txt'];
function sortFilesAndFolders(arr) {
return arr.sort(function (a, b) {
var aIsFolder = isFolder(a),
bIsFolder = isFolder(b);
return aIsFolder !== bIsFolder?
sortByType(aIsFolder) :
sortByName(a, b);
});
function sortByType(aIsFolder) { return aIsFolder? 1 : -1; }
function sortByName(a, b) { return a < b? -1 : +(a > b); }
function isFolder(item) { return item.indexOf('.') === -1; }
}
sortFilesAndFolders(filesAndFolders);
//["file1.txt", "file2.txt", "folder1", "folder2"]
Upvotes: 0
Reputation: 128417
The short answer is that by calling splice
followed by push
, you're adding the element back onto the end (tail) of the array, when in reality you'd want to move it to the front (head) using unshift
.
But there are other, simpler approaches you could take. For example, you could just sort the array using sort
with a custom comparison function:
array.sort(function(x, y) {
var xFolder = x.indexOf('.') == -1 ? 1 : 0;
var yFolder = y.indexOf('.') == -1 ? 1 : 0;
return yFolder - xFolder;
});
This will quickly sort the array, putting all the folders (based on your "no period means it's a folder" criterion) first.
Another option would be to return a new array rather than modify the current one in place. This would be easy to implement:
function putFoldersFirst(entries) {
var folders = [],
files = [];
for (var i = 0; i < entries.length; ++i) {
if (entries[i].indexOf('.') == -1) {
folders.push(entries[i]);
} else {
files.push(entries[i]);
}
}
return folders.concat(files);
}
As always, there's more than one way.
Upvotes: 5
Reputation: 19480
Alternatively you could use Array.prototype.filter
to filter out the items that have a '.'
and the items that don't, and concatenate them:
var items = [ 'a', 'b.c', 'adf', 'd.d', 'a.a' ];
var sortedItems = items.filter( function( item ) {
return item.indexOf( '.' ) !== -1;
} ).concat( items.filter( function( item ) {
return item.indexOf( '.' ) === -1;
} )
);
// you get: ["b.c", "d.d", "a.a", "a", "adf"]
Upvotes: 0
Reputation: 1023
You should use different arrays for looping and for modifying. This is something that has tripped me up in the past plenty of times. As soon as you move something, the index of your loop, or the iterator, isn't guaranteed to point to the correct item anymore.
Just create a temparray and while you iterate the original array, check the correct location in the temparray and copy the value from the original array there, and when you're done, return the sorted array.
That is, of course, if you do want to do it manually and not use a built-in sort as suggested above.
Upvotes: 0