2

I have an array that i want to sort based on another array. If both array is the same length, the code below works fine. However, if my array called order is missing an element, i still want to display that at the end of the new sorted array. Here is a quick example:

//Source arrays
var order = [{_id: '123', type: '2'},{_id: '123', type: '1'}];
var elements = [{_id: '124', type: '1', name: '(should be last, not sorted)'},{_id: '123', type: '1', name: 'second(should be second)'},{_id: '123', type: '2', name: 'third(should be first)'}];

var sorted = [];
for (var i = 0, len = order.length; i < len; i++) {
    var element = elements.filter(function (el) {
		return el.type == order[i]['type'] &&
               el._id == order[i]['_id'];
    });
    sorted.push(element[0]);
}

//Just for testing
var list = document.createElement('ul');
for (var i = 0, len = sorted.length; i < len; i++) {
      var item = document.createElement('li');
      item.appendChild(document.createTextNode(sorted[i]['name']));
      list.appendChild(item);
}
document.getElementById('list').appendChild(list);
<div id="list"></div>

As you can see, now i only have two items in my sorted array. How can i add the missing item(s) from elements at the end?

3 Answers 3

1

You can use array.findIndex to get index and then sort accordingly

var order = [{_id: '123', type: '2'},{_id: '123', type: '1'}];
var elements = [{_id: '124', type: '1', name: '(should be last, not sorted)'},{_id: '123', type: '1', name: 'second(should be second)'},{_id: '123', type: '2', name: 'third(should be first)'}];


elements.sort(function(a, b) {
  var MAX_VALUE = 9999999;
  var index_a = order.findIndex(function(el) {
    return el._id === a._id && el.type === a.type;
  });
  var index_b = order.findIndex(function(el) {
    return el._id === b._id && el.type === b.type;
  });
  
  index_a = index_a < 0? MAX_VALUE : index_a;
  index_b = index_b < 0? MAX_VALUE : index_b;

  return index_a > index_b ? 1 : index_a < index_b ? -1 : 0
});

console.log(elements)

Sign up to request clarification or add additional context in comments.

Comments

1

You could use Array#sort and an object for the sort order. If no order is given, then the element is moved to the end.

function sortWithOrder(array) {
    function getOrder(o) { return (orderObj[o._id] || {})[o.type] || Infinity; }

    var orderObj = Object.create(null);
    array.forEach(function (a, i) {
        orderObj[a._id] = orderObj[a._id] || {};
        orderObj[a._id][a.type] = i + 1;
    });
    return function (a, b) {
        return getOrder(a) - getOrder(b);
    };
}

var order = [{ _id: '123', type: '2' }, { _id: '123', type: '1' }],
    elements = [{ _id: '124', type: '1', name: '(should be last, not sorted)' }, { _id: '123', type: '1', name: 'second(should be second)' }, { _id: '123', type: '2', name: 'third(should be first)' }];

elements.sort(sortWithOrder(order));
console.log(elements);
.as-console-wrapper { max-height: 100% !important; top: 0; }

4 Comments

Any specific reason to define getOrder a local function inside Sort?
@Rajesh, because it is only locally used.
But will that not define/override same function for every iteration. Also does this have any performance benefit? Sorry for so many queries.
@Rajesh, i changed the style. but the original function does not change for every call. it stays the same.
1
var sorted = elements.sort((a, b) => 
               (order.findIndex(i => a._id === i._id && a.type === i.type) + 1 || order.length + 1) 
             - (order.findIndex(i => b._id === i._id && b.type === i.type) + 1 || order.length + 1)
             );

'use strict';

var order = [{
  _id: '123',
  type: '2'
}, {
  _id: '123',
  type: '1'
}];
var elements = [{
  _id: '124',
  type: '1',
  name: '(should be last, not sorted)'
}, {
  _id: '123',
  type: '2',
  name: 'third(should be first)'
}, {
  _id: '124',
  type: '1',
  name: '(should be last, not sorted)'
}, {
  _id: '123',
  type: '1',
  name: 'second(should be second)'
}, {
  _id: '123',
  type: '1',
  name: 'second(should be second)'
}, {
  _id: '123',
  type: '2',
  name: 'third(should be first)'
}, {
  _id: '123',
  type: '2',
  name: 'third(should be first)'
}, {
  _id: '123',
  type: '1',
  name: 'second(should be second)'
}, {
  _id: '124',
  type: '1',
  name: '(should be last, not sorted)'
}];

var sorted = elements.sort(function (a, b) {
  return (order.findIndex(function (i) {
    return a._id === i._id && a.type === i.type;
  }) + 1 || order.length + 1) - (order.findIndex(function (i) {
    return b._id === i._id && b.type === i.type;
  }) + 1 || order.length + 1);
});

//Just for testing
var list = document.createElement('ul');
for (var i = 0, len = sorted.length; i < len; i++) {
      var item = document.createElement('li');
      item.appendChild(document.createTextNode(sorted[i]['name']));
      list.appendChild(item);
}
document.getElementById('list').appendChild(list);
<div id="list"></div>

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.