user99999
user99999

Reputation: 2024

Sorting array of objects where key is a variable

I have the following structure:

var arrOfObjects = [
  {
    folder: {id: 2},
    children: []
  },
  {
    file: {id: 3},
    children: []
  },
  {
    file: {id: 4},
    children: []
  },
  {
    folder: {id: 1},
    children: []
  },
];

And I want to sort it using the following function call:

sortArrOfObjects(arrOfObjects, {
  types: [
    ['file']
  ],
  index: 'id',
  order: 'asc'
});
sortArrOfObjects(arrOfObjects, {
  types: [
    ['folder']
  ],
  index: 'id',
  order: 'asc'
});

The output would be sorted array of first files, and then folders, like:

var arrOfObjects = [
  {
    file: {id: 3},
    children: []
  },
  {
    file: {id: 4},
    children: []
  },
  {
    folder: {id: 1},
    children: []
  },
  {
    folder: {id: 2},
    children: []
  },
];

So I have the following function, calling sort() built-in function on the array, and comparing objects where the given key exists, and skips iteration where the key does not exist in one of the comparators. But it doesn't work, it seems to sort in the completely wrong order. What's wrong?

function sortArrayOfObjects(arr, sortBy) {
    arr.sort(function (a, b) {
        var first = '';
        var second = '';
        for (var i = 0; i < sortBy.types.length; i++) {
            switch (sortBy.types[i].length) {
                case 1:
                    if (a[sortBy.types[i][0]] != undefined) {
                        first = a[sortBy.types[i][0]][sortBy.index].toString().toLowerCase();
                    } else {
                        return;
                    }
                    if (b[sortBy.types[i][0]] != undefined) {
                        second = b[sortBy.types[i][0]][sortBy.index].toString().toLowerCase();
                    } else {
                        return;
                    }
                    break;
                case 2:
                    // not implemented yet
                    break;
                default:
                    break;
            }
        }
        if (first > second) {
            return (sortBy.order == 'asc') ? 1 : -1;
        }
        if (first < second) {
            return (sortBy.order == 'asc') ? -1 : 1;
        }
        return 0;
    });
};

Upvotes: 0

Views: 58

Answers (1)

georg
georg

Reputation: 214949

The technique called "decorate-sort-undecorate" makes jobs like this easy:

var arrOfObjects = [
    {
        folder: {id: 2},
        children: []
    },
    {
        file: {id: 3},
        children: []
    },
    {
        file: {id: 4},
        children: []
    },
    {
        folder: {id: 1},
        children: []
    },
];

result = arrOfObjects
    .map(obj => ('file' in obj) ? [1, obj.file.id, obj] : [2, obj.folder.id, obj])
    .sort((a, b) => a[0] - b[0] || a[1] - b[1])
    .map(x => x[2]);


console.log(result)

Basically, we convert our array like [item, item...] to an array [ [sort-keys, item], [sort-keys, item]..., then sort that array and finally pull our items back - in the right order.

Upvotes: 2

Related Questions