48

I have an array with keys like so:

['asdf12','39342aa','12399','129asg',...] 

and a collection which has these keys in each object like so:

[{guid: '39342aa', name: 'John'},{guid: '129asg', name: 'Mary'}, ... ]

Is there a fast way to sort the collection based on the order of keys in the first array?

2
  • what are language you used? Commented Feb 25, 2015 at 13:12
  • I am using javascript Commented Feb 25, 2015 at 13:19

5 Answers 5

96
var sortedCollection = _.sortBy(collection, function(item){
  return firstArray.indexOf(item.guid)
});
Sign up to request clarification or add additional context in comments.

7 Comments

@silintzir You asked for a fast way to sort the collection in the question. But this is not a fast way, if you really meant the runtime performance.
This works perfectly and is the most elegant solution I have found
does it keep the elements of collection that match with no element from first array or deletes them ?
This is ok, except if the an item isn't on the ordering array it appears first.
@RobertMoskal It's a bit more verbose, but here's a relatively clean fix to that: _.sortBy(collection, (item) => { const index = firstArray.indexOf(item.guid); return index === -1 ? Infinity : index; });
|
16

Here is just a simple add to the accepted answer in case you want to put the unmatched elements at the end of the sortedCollection and not at the beginning:

const last = collection.length;

var sortedCollection = _.sortBy(collection, function(item) {
  return firstArray.indexOf(item.guid) !== -1? firstArray.indexOf(item.guid) : last;
});

1 Comment

Even though this wasn't the accepted answer, to me it is, as it seems more natural to put the unknown elements at the end of the array, after all the sorted items, instead of the beginning
11

Input:

var data1 = ['129asg', '39342aa'];
var data2 = [{
    guid: '39342aa',
    name: 'John'
}, {
    guid: '129asg',
    name: 'Mary'
}];
  1. First create an index object, with _.reduce, like this

    var indexObject = _.reduce(data2, function(result, currentObject) {
        result[currentObject.guid] = currentObject;
        return result;
    }, {});
    
  2. And then map the items of the first array with the objects from the indexObject, like this

    console.log(_.map(data1, function(currentGUID) {
        return indexObject[currentGUID]
    }));
    

Output

[ { guid: '129asg', name: 'Mary' },
  { guid: '39342aa', name: 'John' } ]

Note: This method will be very efficient if you want to sort so many objects, because it will reduce the linear look-up in the second array which would make the entire logic run in O(M * N) time complexity.

1 Comment

I really like this answer, however it doesn't cover cases when there are multiple elements with the same guid. Just pointing it out.
1

This is the efficient & clean way:

(Import lodash identity and sortBy):

TS:

function sortByArray<T, U>({ source, by, sourceTransformer = identity }: { source: T[]; by: U[]; sourceTransformer?: (item: T) => U }) {
  const indexesByElements = new Map(by.map((item, idx) => [item, idx]));
  const orderedResult = sortBy(source, (p) => indexesByElements.get(sourceTransformer(p)));
  return orderedResult;
}

Or in JS:

function sortByArray({ source, by, sourceTransformer = _.identity }) {
    const indexesByElements = new Map(by.map((item, idx) => [item, idx]));
    const orderedResult = _.sortBy(source, (p) => indexesByElements.get(sourceTransformer(p)));
    return orderedResult;
}

1 Comment

I really like this one.
0

You can use indexBy(), and at() to sort your collection. The advantage being that concise code and performance. Using sortBy() here does the trick, but your external array is already sorted:

var ids = [ 'cbdbac14', 'cf3526e2', '189af064' ];

var collection = [
    { guid: '189af064', name: 'John' },
    { guid: 'cf3526e2', name: 'Julie' },
    { guid: 'cbdbac14', name: 'James' }
];

_(collection)
    .indexBy('guid')
    .at(ids)
    .pluck('name')
    .value();
// → [ 'James', 'Julie', 'John' ]

Using at(), you can iterate over the sorted external collection, building a new collection from the source collection. The source collection has been transformed into an object using indexBy(). You do this so at() has key-based access for each of it's ids.

1 Comment

this answer should be updated as the lodash way and functions has changed.

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.