skip to Main Content

I am trying to sort the array elements as below:

let defaultOrder = [
    {'item': 'Pen', 'value': '5'}, 
    {'item': 'Spike', 'value': '5'}, 
    {'item': 'Pencil', 'value': '5'}, 
    {'item': 'Ink', 'value': '5'}, 
    {'item': 'Mail', 'value': '5'}, 
    {'item': 'Rubber', 'value': '5'}
];

let items = [
    {'item': 'Spike', 'value': '5'}, 
    {'item': 'Duck', 'value': '5'}, 
    {'item': 'Ink', 'value': '5'}, 
    {'item': 'Pencil', 'value': '5'}, 
    {'item': 'Rubber', 'value': '5'}, 
    {'item': 'Mail', 'value': '5'}, 
    {'item': 'Pen', 'value': '5'} 
];

let orderedItems = items.sort(function (a,b){
    return defaultOrder.indexOf(a.item) - defaultOrder.indexOf(b.item)
});

I am able to sort the elements, but how to make the unsorted elements, from above: {'item': 'Duck', 'value': '5'}, to get appended at the very end of the sorted items?

4

Answers


  1. You could take an object for the positions and a default value for unknown items.

    const
        defaultOrder = [{ item: 'Pen', value: '5' }, { item: 'Spike', value: '5' }, { item: 'Pencil', value: '5' }, { item: 'Ink', value: '5' }, { item: 'Mail', value: '5' }, { item: 'Rubber', value: '5' }],
        order = Object.fromEntries(defaultOrder.map(({ item }, index) => [item, index + 1])),
        items = [{ item: 'Spike', value: '5' }, { item: 'Duck', value: '5' }, { item: 'Ink', value: '5' }, { item: 'Pencil', value: '5' }, { item: 'Rubber', value: '5' }, { item: 'Mail', value: '5' }, { item: 'Pen', value: '5' }];
    
    items.sort((a, b) => (order[a.item] || Infinity) - (order[b.item] || Infinity));
    
    console.log(items);
    .as-console-wrapper { max-height: 100% !important; top: 0; }
    Login or Signup to reply.
  2. Check if an item isn’t found in defaultOrder, and return an appropriate value so it will sort at the end.

    let defaultOrder = [
        {'item': 'Pen', 'value': '5'}, 
        {'item': 'Spike', 'value': '5'}, 
        {'item': 'Pencil', 'value': '5'}, 
        {'item': 'Ink', 'value': '5'}, 
        {'item': 'Mail', 'value': '5'}, 
        {'item': 'Rubber', 'value': '5'}
    ];
    
    let items = [
        {'item': 'Spike', 'value': '5'}, 
        {'item': 'Duck', 'value': '5'}, 
        {'item': 'Ink', 'value': '5'}, 
        {'item': 'Pencil', 'value': '5'}, 
        {'item': 'Rubber', 'value': '5'}, 
        {'item': 'Mail', 'value': '5'}, 
        {'item': 'Pen', 'value': '5'} 
    ];
    
    let orderedItems = items.sort(function (a,b){
        let aPos = defaultOrder.findIndex(el => el.item == a.item);
        let bPos = defaultOrder.findIndex(el => el.item == b.item);
        if (aPos == -1) {
          return 1;
        } else if (bPos == -1) {
          return -1;
        } else {
          return aPos - bPos;
        }
    });
    
    console.log(orderedItems);
    Login or Signup to reply.
  3. The way to do that is to check if exactly one of those is not found in the defaultOrder array, then return 1 to -1 to signify the order.

    Additionally, you need to use Array.prototype.findIndex to find an object with that property. Originally, you were searching for the string 'Pen' (for example) instead of an object that has the .item property as 'Pen'

    let defaultOrder = [
        {'item': 'Pen', 'value': '5'}, 
        {'item': 'Spike', 'value': '5'}, 
        {'item': 'Pencil', 'value': '5'}, 
        {'item': 'Ink', 'value': '5'}, 
        {'item': 'Mail', 'value': '5'}, 
        {'item': 'Rubber', 'value': '5'}
    ];
    
    let items = [
        {'item': 'Spike', 'value': '5'}, 
        {'item': 'Duck', 'value': '5'}, 
        {'item': 'Ink', 'value': '5'}, 
        {'item': 'Pencil', 'value': '5'}, 
        {'item': 'Rubber', 'value': '5'}, 
        {'item': 'Mail', 'value': '5'}, 
        {'item': 'Pen', 'value': '5'} 
    ];
    
    let orderedItems = items.sort(function (a,b){
        let aIndex = defaultOrder.findIndex((other) => other.item === a.item);
        let bIndex = defaultOrder.findIndex((other) => other.item === b.item);
        
        if (aIndex === bIndex) return 0;
        if (aIndex === -1) return 1;
        if (bIndex === -1) return -1;
        return aIndex - bIndex;
    });
    
    console.log(orderedItems);
    /* fill the screen on Stack Overflow */
    .as-console-wrapper { max-height: 100% !important; top: 0; }
    Login or Signup to reply.
  4. You don’t need to use Array::sort() since you have already a sorted order in the first array (so use an already known information to your advantagle).

    1. Get already sorted indices from the first array by item names
    2. Build a new array with the indices map + put not found items to the end (after the sorted array length):
    let defaultOrder = ['Pen', 'Spike', 'Pencil', 'Ink', 'Mail', 'Rubber']
    
    let items = [
        {'item': 'Spike', 'value': '5'}, 
        {'item': 'Duck', 'value': '5'}, 
        {'item': 'Ink', 'value': '5'}, 
        {'item': 'Pencil', 'value': '5'}, 
        {'item': 'Rubber', 'value': '5'}, 
        {'item': 'Mail', 'value': '5'}, 
        {'item': 'Pen', 'value': '5'} 
    ];
    
    const indices = {};
    defaultOrder.forEach((item, index) => indices[item] = index);
    
    const result = Array(items.length);
    let unsortedPos = defaultOrder.length;
    for(const item of items){
      result[indices[item.item] ?? unsortedPos++] = item;
    }
    
    
    console.log(result);
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search