Sort an array of objects based on another array of ids

大城市里の小女人 提交于 2019-11-26 22:06:13

问题


I have 2 arrays

a = [2,3,1,4]
b = [{id: 1}, {id: 2}, {id: 3}, {id: 4}]

How do I get b sorted based on a? My desired output would be

c = [{id: 2}, {id: 3}, {id: 1}, {id: 4}]

I would prefer to use Ramda or regular JS.


回答1:


Ramda really shines for these types of problems.

Where the size of the data is small, we can use a simple reduce function, and indexOf helper.

// match id of object to required index and insert
var sortInsert = function (acc, cur) {
  var toIdx = R.indexOf(cur.id, a);
  acc[toIdx] = cur;
  return acc;
};

// point-free sort function created
var sort = R.reduce(sortInsert, []);

// execute it now, or later as required
sort(b);
// [ { id: 2 }, { id: 3 }, { id: 1 }, { id: 4 } ]

This works well for small(ish) data sets but the indexOf operation on every iteration through the reduction is inefficient for large data sets.

We can remedy this by tackling the problem from the other side, lets use groupBy to group our objects by their id, thus creating a dictionary lookup (much better!). We can then simply map over the required indexes and transform them to their corresponding object at that position.

And here is the solution using this approach:

var groupById = R.groupBy(R.prop('id'), b);

var sort = R.map(function (id) {
    return groupById[id][0];
});

sort(a);
// [ { id: 2 }, { id: 3 }, { id: 1 }, { id: 4 } ]

Finally, this is yet another solution, which is very succinct:

R.sortBy(R.pipe(R.prop('id'), R.indexOf(R.__, a)))(b);
// [ { id: 2 }, { id: 3 }, { id: 1 }, { id: 4 } ]

I love the way you can compose functions with behaviour and separate the algorithm from the data upon which it acts using Ramda. You end up with very readable, and easy to maintain code.




回答2:


You can provide a custom comparison function to JavaScript's Array#sort method.

Use the custom comparison function to ensure the sort order:

var sortOrder = [2,3,1,4],
    items     = [{id: 1}, {id: 2}, {id: 3}, {id: 4}];

items.sort(function(a, b){
  return sortOrder.indexOf(a.id) - sortOrder.indexOf(b.id);
});



回答3:


Or may be simpler

b.sort(function(obj1,obj2){
   return a.indexOf(obj1.id) > a.indexOf(obj2.id)
});



回答4:


This solution uses Array#sort with a helper object c for the indices.

{
    "1": 2,
    "2": 0,
    "3": 1,
    "4": 3
}

var a = [2, 3, 1, 4],
    b = [{ id: 1 }, { id: 2 }, { id: 3 }, { id: 4 }],
    c = a.reduce(function (r, a, i) {
        r[a] = i;
        return r;
    }, {});

b.sort(function (x, y) {
    return c[x.id] - c[y.id];
});

document.write('<pre>' + JSON.stringify(b, 0, 4) + '</pre>');

For greater objects, I suggest to use Sorting with map.




回答5:


Using Ramda, you have to map objects in b to their index via the mapObjIndexed function and then search the value in a. You can try it here.

var a = [2,3,1,4];
var b =  [{id: 1}, {id: 2}, {id: 3}, {id: 4}]
R.find( R.propEq('id', a[0]), b )
R.values(R.mapObjIndexed(  (num, key, obj) => R.find( R.propEq('id', a[key]), b ) , b))



回答6:


You could just create c based off of a without ever using b:

var a = [2,3,1,4];
var c = [];

for(var i = 0; i < a.length; i++){

    c.append({id:a[i]);

}

Hope this helps!




回答7:


Plain javascript, using some methods of the Array (ES2015 standard)

var a = [2,3,1,4];
var b = [{id: 1}, {id: 2}, {id: 3}, {id: 4}];
var c = [];

a.forEach(el => c.push(b.find(e => e.id == el)));

document.write(JSON.stringify(c, 0, 2));


来源:https://stackoverflow.com/questions/35538509/sort-an-array-of-objects-based-on-another-array-of-ids

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!