如何根据另一个数组的顺序对对象数组进行排序?
Posted
技术标签:
【中文标题】如何根据另一个数组的顺序对对象数组进行排序?【英文标题】:How do I sort an array of objects based on the ordering of another array? 【发布时间】:2012-04-03 02:17:22 【问题描述】:我有一个对象列表:
[ id: 4, name:'alex' , id: 3, name:'jess' , id: 9, name:'...' , id: 1, name:'abc' ]
我还有另一个“顺序”正确的列表。
[ 3, 1, 9, 4]
如何根据键“id”将第一个列表与第二个列表的顺序相匹配? 结果应该是:
[ id: 3, name:'jess' , id: 1, name:'abc' , id: 9, name:'...' , id: 4, name:'alex' ]
【问题讨论】:
【参考方案1】:我认为最好的方法是将第一个列表的所有元素放入一个散列中,使用 id 值作为属性名称;然后通过遍历 id 列表、查找散列中的每个对象并将其附加到列表中来构建第二个列表。
【讨论】:
【参考方案2】:将列表变成一个对象,这样您将拥有order = 3:0, 1:1, 9:2, 4:3
,而不是order = [3, 1, 9, 4]
,然后执行以下操作
function ( order, objects )
ordered_objects = []
for( var i in objects )
object = objects[i]
ordered_objects[ order[ object.id ] ] = object
return ordered_objects
【讨论】:
我认为您缺少s
...object = object[i]
。【参考方案3】:
有点像这样:
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]]);
这个想法是将来自data
的项目放入一个对象中,使用id 作为属性名称——这样您就可以检索具有给定id 的项目,而无需搜索数组。 (否则,您必须使用嵌套循环,或在单个循环中使用 Array.indexOf()
函数,就性能而言,这实际上是一个嵌套循环。)
这假定data
中没有两个元素具有相同的 id 属性。
【讨论】:
【参考方案4】: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);
【讨论】:
假设没有重复的 id,如果你在if
块内放一个 break
可以加快速度。【参考方案5】:
嗯,简单的答案是,“对于这么小的一组数据,任何比无限循环成本更低的东西基本上都不会引起注意。”但是让我们试着回答这个“正确”。
第二个数组中的顺序没有押韵或理由,它只是第一个数组主键上的外键列表(使用 SQL 术语)。因此,将它们视为键,并且我们希望有效地查找这些键,哈希表(对象)可能会以O(n)
方式(2*n
,真的)最快“排序”,假设第一个数组称为objArray
,第二个数组称为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;
应该这样做。我想不出任何不需要两次通过的方法。 (或者一个接一个,像这样,或者通过数组多次传递并splice
找出找到的元素,例如,这对于反向排序的数据可能会变得很昂贵。)
【讨论】:
您可以通过将 objArray.length 移动到 var 来进一步加快速度,这样就不会每次都对其进行评估。 (但你已经知道了:)这得到了我的 +1【参考方案6】:您可以使用 Alasql 库和两个数组的简单 SELECT JOIN 来做到这一点。
唯一的一点:Alasql 将源数据理解为数组数组或对象数组,所以你 需要将简单数组转换为数组数组(参见步骤 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]);
试试这个例子at jsFiddle。
【讨论】:
【参考方案7】:我介入了这个问题并用一个简单的.sort
解决了它
假设您要排序的列表存储在变量needSort
中,并且具有顺序的列表在变量order
中,并且两者都在同一范围内,您可以像这样运行.sort
:
needSort.sort(function(a,b)
return order.indexOf(a.id) - order.indexOf(b.id);
);
它对我有用,希望它有所帮助。
【讨论】:
你的3行可以压缩:return order.indexOf(a.id) < order.indexOf(b.id) ? -1 : 1;
JSFiddle:jsfiddle.net/zamnuts/guyjm0za
感谢您的建议,我已将其添加到答案中。
嘿,如果两个数组的长度,即要排序的实际数组和顺序数组不同,这会起作用吗?而且,在这种情况下,如果我们需要进一步按 id 对其进行排序,如果 2 个 id 相同,我们该怎么做。
不将此标记为答案,您就是在犯罪。
我认为这个答案有问题,因为如果两个索引相等,排序函数不会返回0
。这是病态的,因为只有当需要排序中的两个元素具有相同的id
时才会发生这种情况。因此我会使用return order.indexOf(a.id) - order.indexOf(b.id);
【参考方案8】:
我如何解决几乎相同的问题
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));
【讨论】:
此代码假定[3, 1, 9, 4]
中的每个元素在data
中都有一个元素。如果数据只包含一个子集,那么排序列表可能包含undefined
元素。
是的。不过,可以通过附加 .filter(o => o)
之类的内容轻松修复,具体取决于您要查找的内容。【参考方案9】:
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));
【讨论】:
以上是关于如何根据另一个数组的顺序对对象数组进行排序?的主要内容,如果未能解决你的问题,请参考以下文章