-4

I have two arrays.

itemsArray = 
[
{ id: 8, name: 'o'},
{ id: 7, name: 'g'},
{ id: 6, name: 'a'},
{ id: 5, name: 'k'},
{ id: 4, name: 'c'}
]

sortArray = [4,5]

How can i sort itemsArray by sortArray (lodash or pure), but i want to for this:

newArray = 
[
{ id: 4, name: 'c'},
{ id: 5, name: 'k'},
{ id: 8, name: 'o'},
{ id: 7, name: 'g'},
{ id: 6, name: 'a'}
]
Serdar
  • 43
  • 1
  • 4
  • 2
    Possible duplicate of [How do I sort an array of objects based on the ordering of another array?](https://stackoverflow.com/questions/9755889/how-do-i-sort-an-array-of-objects-based-on-the-ordering-of-another-array) and [Sort an array of objects based on another array of ids](https://stackoverflow.com/questions/35538509/sort-an-array-of-objects-based-on-another-array-of-ids) and [Sort array containing objects based on another array using _Underscore](https://stackoverflow.com/questions/28673656/sort-array-containing-objects-based-on-another-array-using-underscore). Please search before asking. – str Jan 17 '19 at 08:41

2 Answers2

1

In a case like this where you want to sort on multiple levels, you need to sort them in descending order of importance inside your sorting function.

In this case we sort regularly on cases where both elements are either in or not in the sorting array.

var itemsArray = [
    { id: 8, name: 'o' },
    { id: 7, name: 'g' },
    { id: 6, name: 'a' },
    { id: 5, name: 'k' },
    { id: 4, name: 'c' }
];
var sortArray = [4, 5];
var sortedItemsArray = itemsArray.sort(function (a, b) {
    if (sortArray.includes(a.id) == sortArray.includes(b.id)) { //both or neither are in sort array
        return b.id - a.id;
    }
    else if (sortArray.includes(a.id)) { //only a in sort array
        return -1;
    }
    else { //only b in sort array
        return 1;
    }
});
console.log(sortedItemsArray);

The above snippet could be expanded in multiple ways, but a popular approach is to separate it into several sorting steps.

var itemsArray = [
    { id: 8, name: 'o' },
    { id: 7, name: 'g' },
    { id: 6, name: 'a' },
    { id: 5, name: 'k' },
    { id: 4, name: 'c' }
];
var sortArray = [4, 5];
function sortId(a, b) {
    return b.id - a.id;
}
function sortIdByList(a, b) {
    if (sortArray.includes(a.id)) {
        return -1;
    }
    if (sortArray.includes(b.id)) {
        return 1;
    }
    return 0;
}
//TEST
var sortedItemsArray = itemsArray
    .sort(sortId)
    .sort(sortIdByList);
console.log(sortedItemsArray);

This pattern can be easier to maintain as each step is clearly labeled and the functions can be reused in other sorting cases.

The only downside to this pattern is that you end up iterating over the list multiple times, thus increasing the time to sort. Usually this is a non-issue but on very large lists this can be significant.

Sort by array index only

As the comments points out i misread the question, so my previous two sorting snippets doesn't necessarily give the desired result.

This version sorts only by id index in the sorting array:

var itemsArray = [
    { id: 8, name: 'o' },
    { id: 7, name: 'g' },
    { id: 6, name: 'a' },
    { id: 5, name: 'k' },
    { id: 4, name: 'c' }
];
var sortArray = [4, 5];
//TEST
var sortedItemsArray = itemsArray
    .sort(function (a, b) {
    //Calculate index value of a
    var A = sortArray.indexOf(a.id);
    if (A == -1) {
        A = sortArray.length;
    }
    //Calculate index value of b
    var B = sortArray.indexOf(b.id);
    if (B == -1) {
        B = sortArray.length;
    }
    //Return comparison
    return A - B;
});
console.log(sortedItemsArray);
Emil S. Jørgensen
  • 6,216
  • 1
  • 15
  • 28
  • This does not seem to work. Also, you should not answer questions which are clearly duplicates. – str Jan 17 '19 at 08:52
  • Notice you compare return `b.id - a.id;` and not by the index of the id in the array which may be difference. Think of case when `sortIdsArr = [7,3,9]` – dWinder Jan 17 '19 at 08:57
0

You could take the indices of the array for keeping the relative position and take the special items with a negative index to top for sorting.

Then sort the array by taking the indices.

var array = [{ id: 8, name: 'o' }, { id: 7, name: 'g' }, { id: 6, name: 'a' }, { id: 5, name: 'k' }, { id: 4, name: 'c' }],
    sortArray = [4, 5],
    indices = array.reduce((r, { id }, i) => (r[id] = i, r), {});
    
sortArray.forEach((id, i, { length }) => indices[id] = i - length);

array.sort(({ id: a }, { id: b }) => indices[a] - indices[b]);

console.log(array);
console.log(indices);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Nina Scholz
  • 376,160
  • 25
  • 347
  • 392
  • You just answered a duplicate question with a [duplicate answer by yourself](https://stackoverflow.com/a/35538596/906113). DRY. – str Jan 17 '19 at 08:59
  • @str, not completerly, the other answer has all new positions, but here parts of the items should stay relatively. – Nina Scholz Jan 17 '19 at 09:00