根据另一个 id 数组对一组对象进行排序

IT技术 javascript ramda.js
2021-02-05 21:52:20

我有 2 个数组

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

我如何b根据 进行排序a我想要的输出是

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

我更喜欢使用 Ramda 或常规 JS。

6个回答

您可以为 JavaScript 的Array#sort方法提供自定义比较函数

使用自定义比较函数来保证排序顺序:

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);
});

目录

  • 如果 compareFunction(a, b) 返回小于 0,则将 a 排序到低于 b 的索引(即 a 在前)。
  • 如果 compareFunction(a, b) 返回 0,则 a 和 b 彼此保持不变,但相对于所有不同元素进行排序。注意:ECMAscript 标准不保证这种行为,因此,并非所有浏览器(例如至少可以追溯到 2003 年的 Mozilla 版本)都尊重这一点。
  • 如果 compareFunction(a, b) 返回大于 0,则将 b 排序到小于 a 的索引(即 b 在前)。

Hitmands 对上述解决方案做出了非常中肯的评论:

这种方法是 O(n2),并且会导致大型列表中的性能问题。最好先构建字典,使其保持 O(n)

因此,上述解决方案最终可能不会像您在大型输入中所需要的那样快。

要实施 Hitmands 的建议:

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

const itemPositions = {};
for (const [index, id] of sortOrder.entries()) {
  itemPositions[id] = index;
}

items.sort((a, b) => itemPositions[a.id] - itemPositions[b.id]);
这种方法是O(n2),并且会导致大型列表中的性能问题。最好先建立字典,以便它保持O(n)
2021-04-11 21:52:20

Ramda真正解决了这些类型的问题。

在数据量较小的地方,我们可以使用一个简单的reduce函数和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 } ]

这适用于小型(ish)数据集,但每次迭代indexOf操作通过减少对大型数据集效率低下。

我们可以通过从另一方面解决这个问题来解决这个问题,让我们使用groupBy根据对象的 id 对我们的对象进行分组,从而创建一个字典查找(好多了!)。然后我们可以简单地映射所需的索引并将它们转换为相应位置的对象。

这是使用这种方法的解决方案:

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 } ]

最后,这是另一个非常简洁的解决方案:

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

我喜欢您可以使用行为组合函数并将算法与其使用Ramda 所依据的数据分离的方式您最终会得到非常易读且易于维护的代码。

我不认为 Ramda 在这里闪耀,我认为这些解决方案的可读性不如纯 JS 替代方案......
2021-03-13 21:52:20
你能做sortInsert一个纯函数吗?:)
2021-04-03 21:52:20

使用 ES6 映射和查找

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

// map over a, find it in b and return    
const c = a.map((i) => b.find((j) => j.id === i));

您可以ca不使用情况下创建基于b

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

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

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

}

希望这可以帮助!

可能不完全是问题所要求的,但仍然是跳出框框思考的有用视角
2021-03-19 21:52:20

或者可能更简单

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