Join the Stack Overflow Community
Stack Overflow is a community of 6.6 million programmers, just like you, helping each other.
Join them; it only takes a minute:
Sign up

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' } ]
share|improve this question

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) ? -1 : 1;
});

It worked for me, hope it helps.

share|improve this answer
2  
Your 3 lines can be condensed: return order.indexOf(a.id) < order.indexOf(b.id) ? -1 : 1; JSFiddle: jsfiddle.net/zamnuts/guyjm0za – zamnuts Feb 20 '15 at 18:37
    
Thanks for the suggestion, I've added it to the answer. – HClx Feb 23 '15 at 19:00
    
Hey, will this work, if the length of both arrays i.e. the actual array to be sorted and order array are different? And also, in that case, if we need to further sort it by id, in case 2 id's are same, how can we do that. – whyAto8 Jul 13 '16 at 9:33

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 spliceing out the found elements, which can get costly with backwards-sorted data, for instance.)

share|improve this answer
    
@David... nice :) – Hristo Mar 18 '12 at 4:30
    
You could speed this up further by moving the objArray.length to a var so it doesn't get evaluated every time. (but you already know that:) this gets +1 from me – Aran Mulholland Jul 11 '13 at 4:21

DEMO

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);​
share|improve this answer
    
Assuming there are no repeated ids you could speed this up if you put a break inside the if block. – nnnnnn Mar 18 '12 at 4:20
    
i thought of that too, just updated it :D – Joseph the Dreamer Mar 18 '12 at 4:25
    
Upvote for breakdancing. :) – David Ellis Mar 18 '12 at 4:52

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.

share|improve this answer

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
}
share|improve this answer
    
I think you're missing an s... object = object[i]. – James Montagne Mar 18 '12 at 4:10

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.

share|improve this answer

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.

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.