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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/9755889/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-26 07:44:39  来源:igfitidea点击:

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

javascriptarraysjsonalgorithmsorting

提问by TIMEX

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"? The result should be:

如何根据键“id”将第一个列表与第二个列表的顺序匹配?结果应该是:

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

回答by HClx

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 needSortand the list with the order is in the variable orderand the both are in the same scope you can run a .sortlike 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.

它对我有用,希望它有所帮助。

回答by Frans

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

回答by Frans

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. 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 objArrayand the second array is called keyArray:

第二个数组中的顺序没有韵律或理由,它只是第一个数组主键上的外键列表(使用 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;

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 spliceing out the found elements, which can get costly with backwards-sorted data, for instance.)

那应该这样做。我想不出任何不需要两次通过的方法。(一个接一个,像这样,或者通过数组多次传递并splice取出找到的元素,例如,使用向后排序的数据可能会变得昂贵。)

回答by Ernest Friedman-Hill

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

回答by Doboy

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
}

回答by nnnnnn

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 datainto 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. (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.)

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

This assumes that no two elements in datahave the same id property.

这假设没有两个元素data具有相同的 id 属性。

回答by Joseph

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

回答by agershun

You can do it with Alasqllibrary 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试试这个例子。