简体   繁体   English

如何根据另一个数组的顺序对对象数组进行排序?

[英]How do I sort an array of objects based on the ordering of another array?

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"?如何根据键“id”将第一个列表与第二个列表的顺序匹配? The result should be:结果应该是:

[ { id: 3, name:'jess' }, { id: 1, name:'abc' }, { id: 9, name:'...' }, { id: 4, name:'alex' } ]

I stepped in this problem and solved it with a simple .sort我介入了这个问题并用一个简单的.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并且具有顺序的列表在变量order并且两者都在同一范围内,您可以像这样运行.sort

needSort.sort(function(a,b){
  return order.indexOf(a.id) - order.indexOf(b.id);
});

It worked for me, hope it helps.它对我有用,希望它有所帮助。

How I solved pretty much the same issue我如何解决几乎相同的问题

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

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.第二个数组中的顺序没有韵律或理由,它只是第一个数组主键上的外键列表(使用 SQL 术语)。 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 :因此,将它们视为键,并且我们希望有效查找这些键,哈希表(对象)可能会以O(n)方式(实际上是2*n O(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;

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 splice ing out the found elements, which can get costly with backwards-sorted data, for instance.) (一个接一个,像这样,或者通过数组多次传递并splice出找到的元素,例如,使用向后排序的数据可能会变得昂贵。)

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;我认为您会发现的最好方法是使用 id 值作为属性名称将第一个列表的所有元素放入一个散列中; 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.然后通过遍历 id 列表、查找哈希中的每个对象并将其附加到列表中来构建第二个列表。

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将列表变成一个对象,而不是order = [3, 1, 9, 4]您将拥有order = { 3:0, 1:1, 9:2, 4:3} ,然后执行以下操作

function ( order, objects ){
     ordered_objects = []
     for( var i in objects ){
           object = objects[i]
           ordered_objects[ order[ object.id ] ] = object
     }
     return ordered_objects
}

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.这个想法是使用 id 作为属性名称将data的项目放入对象中 - 这样您就可以检索具有给定 id 的项目,而无需搜索数组。 (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.) (否则,您必须在单个循环中使用嵌套循环或Array.indexOf()函数,就性能而言,这实际上将成为嵌套循环。)

This assumes that no two elements in data have the same id property.这假设data中没有两个元素具有相同的 id 属性。

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

You can do it with Alasql library with simple SELECT JOIN of two arrays.您可以使用Alasql库通过两个数组的简单 SELECT JOIN 来完成。

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)唯一的一件事: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]);

Try this example at jsFiddle .在 jsFiddle试试这个例子。

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM