Reputation: 4442
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?
Upvotes: 2
Views: 91
Reputation: 15566
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>
Upvotes: 1
Reputation: 386654
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; }
Upvotes: 1
Reputation: 24925
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)
Upvotes: 1