Reputation: 271614
I have a list of objects:
[ { id: 4, name:'alex' }, { id: 3, name:'jess' }, { id: 9, name:'...' }, { id: 1, name:'abc' } ]
I have another list with the right "order".
[ 3, 1, 9, 4]
How can I match the first list to the ordering of the second list, based on the key "id"? The result should be:
[ { id: 3, name:'jess' }, { id: 1, name:'abc' }, { id: 9, name:'...' }, { id: 4, name:'alex' } ]
Upvotes: 15
Views: 17294
Reputation: 1205
const obj = [ { id: 4, name:'alex' }, { id: 3, name:'jess' }, { id: 9, name:'...' }, { id: 1, name:'abc' } ];
const id = [ 3, 1, 9, 4];
const result = id.map(i => obj.find(j => j.id === i));
Upvotes: 0
Reputation: 481
I stepped in this problem and solved it with a simple .sort
Assuming that your list to be sorted is stored in the variable needSort
and the list with the order is in the variable order
and the both are in the same scope you can run a .sort
like this:
needSort.sort(function(a,b){
return order.indexOf(a.id) - order.indexOf(b.id);
});
It worked for me, hope it helps.
Upvotes: 30
Reputation: 1448
How I solved pretty much the same issue
data = [{ id: 4, name:'alex' }, { id: 3, name:'jess' }, { id: 9, name:'...' }, { id: 1, name:'abc' } ];
sorted = [3, 1, 9, 4].map((i) => data.find((o) => o.id === i));
Upvotes: 10
Reputation: 4107
You can do it with Alasql library with simple SELECT JOIN of two arrays.
The only one thing: Alasql understands source data as array of arrays or array of objects, so you need to convert simple array to array of arrays (see Step 1)
var data1 = [ { id: 3, name:'jess' }, { id: 1, name:'abc' },
{ id: 9, name:'...' }, { id: 4, name:'alex' } ];
var data2 = [3, 1, 9, 4];
// Step 1: Convert [3,1,9,4] to [[3],[1],[9],[4]]
var data2a = data2.map(function(d){return [d]});
// Step 2: Get the answer
var res = alasql('SELECT data1.* FROM ? data1 JOIN ? data2 ON data1.id = data2.[0]',
[data1,data2a]);
Try this example at jsFiddle.
Upvotes: 0
Reputation: 119827
function sort(array, order) {
//create a new array for storage
var newArray = [];
//loop through order to find a matching id
for (var i = 0; i < order.length; i++) {
//label the inner loop so we can break to it when match found
dance:
for (var j = 0; j < array.length; j++) {
//if we find a match, add it to the storage
//remove the old item so we don't have to loop long nextime
//and break since we don't need to find anything after a match
if (array[j].id === order[i]) {
newArray.push(array[j]);
array.splice(j,1);
break dance;
}
}
}
return newArray;
}
var newOrder = sort(oldArray,[3, 1, 9, 4]);
console.log(newOrder);
Upvotes: 1
Reputation:
Well, the simple answer would be, "for a set of data this small, anything less costly than an infinite loop will be basically unnoticeable." But let's try to answer this "right."
There's no rhyme or reason to the order in the second array, it's just a list of foreign keys (to use SQL terminology) on the primary keys of the first array. So, thinking of them as keys, and that we want efficient lookup of those keys, a hash table (object) would probably "sort" this the quickest, in an O(n)
fashion (2*n
, really) assuming the first array is called objArray
and the second array is called keyArray
:
// Create a temporary hash table to store the objects
var tempObj = {};
// Key each object by their respective id values
for(var i = 0; i < objArray.length; i++) {
tempObj[objArray[i].id] = objArray[i];
}
// Rebuild the objArray based on the order listed in the keyArray
for(var i = 0; i < keyArray.length; i++) {
objArray[i] = tempObj[keyArray[i]];
}
// Remove the temporary object (can't ``delete``)
tempObj = undefined;
And that should do it. I can't think of any method that doesn't require two passes. (Either one after the other, like this, or by passing multiple times through the array and splice
ing out the found elements, which can get costly with backwards-sorted data, for instance.)
Upvotes: 7
Reputation: 150010
A little something like this:
var data = [ { id: 4, name:'alex' }, { id: 3, name:'jess' }, { id: 9, name:'...' }, { id: 1, name:'abc' } ],
order = [ 3, 1, 9, 4],
sorted = [],
items = {},
i;
for (i = 0; i < data.length; i++)
items[data[i].id] = data[i];
for (i = 0; i < order.length; i++)
sorted.push(items[order[i]]);
The idea is to put the items from data
into an object using the ids as property names - that way you can retrieve the item with a given id without without having to search through the array. (Otherwise you'd have to use a nested loop, or the Array.indexOf()
function inside a single loop which is effectively going to be a nested loop as far as performance.)
This assumes that no two elements in data
have the same id property.
Upvotes: 1
Reputation: 11082
Make the list into a object so instead of order = [3, 1, 9, 4]
you will have order = { 3:0, 1:1, 9:2, 4:3}
, then do the following
function ( order, objects ){
ordered_objects = []
for( var i in objects ){
object = objects[i]
ordered_objects[ order[ object.id ] ] = object
}
return ordered_objects
}
Upvotes: 1
Reputation: 81674
I think the best way you'll find is to put all the elements of the first list into a hash using the id values as the property name; then build the second list by iterating over the list of ids, looking up each object in the hash, and appending it to the list.
Upvotes: 1