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

时间:2012-03-18 04:02:42

标签: javascript arrays json algorithm sorting

我有一个对象列表:

[ { 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' } ]

9 个答案:

答案 0 :(得分:26)

我介入了这个问题并用简单的.sort

解决了这个问题

假设您要排序的列表存储在变量needSort中,并且带有顺序的列表位于变量order中且两者都在同一范围内,您可以运行{{1像这样:

.sort

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

答案 1 :(得分:7)

嗯,简单的答案是,“对于一组这么小的数据,任何比无限循环更低成本的数据基本上都是不可察觉的。”但是,让我们试着回答这个“正确的问题。”

第二个数组中的顺序没有押韵或理由,它只是第一个数组主键上的外键列表(使用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找出找到的元素,例如,对于向后排序的数据可能会花费很多。)

答案 2 :(得分:6)

我如何解决几乎相同的问题

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 :(得分:2)

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

答案 4 :(得分:1)

我认为您找到的最佳方法是使用id值作为属性名称将第一个列表的所有元素放入哈希值;然后通过迭代id列表构建第二个列表,查找哈希中的每个对象,并将其附加到列表中。

答案 5 :(得分:1)

将列表设为对象,而不是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
}

答案 6 :(得分:1)

有点像这样:

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

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

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

答案 7 :(得分:0)

你可以使用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

答案 8 :(得分:0)

# Failed Approach 1
df['listings'] = np.where(df['listings'].isnull(), ['none']*4, df['listings'])

# Failed Approach 2
df['listings'].fillna(['none']*4)