Подтвердить что ты не робот

Как отсортировать массив объектов на основе упорядочения другого массива?

У меня есть список объектов:

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

Ответ 1

Я вступил в эту проблему и решил ее с помощью простого .sort

Предполагая, что ваш список будет отсортирован, сохраняется в переменной needSort, а список с порядком находится в переменной order, и оба они находятся в той же области действия, что вы можете запустить .sort следующим образом:

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

Это сработало для меня, надеюсь, что это поможет.

Ответ 2

Ну, простой ответ был бы: "для набора данных это мало, что-нибудь менее дорогое, чем бесконечный цикл, будет в основном незаметным". Но постарайтесь ответить на это "правильно".

Там нет рифмы или причины для порядка во втором массиве, это просто список внешних ключей (для использования терминологии 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 из найденных элементов, которые могут дорого стоить с данными, отсортированными по обратной стороне).

Ответ 3

Как я решил почти такую ​​же проблему

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

Ответ 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);​

Ответ 5

Я думаю, что лучший способ, который вы найдете, - поместить все элементы первого списка в хэш, используя значения id в качестве имени свойства; затем создайте второй список, итерируя по списку идентификаторов, просматривая каждый объект в хеше и добавляя его в список.

Ответ 6

Сделайте список в объект, поэтому вместо 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
}

Ответ 7

Немного что-то вроде этого:

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 в объект, используя идентификаторы как идентификаторы свойств - таким образом вы можете получить элемент с данным идентификатором без необходимости поиска по массиву. (В противном случае вам нужно будет использовать вложенный цикл или функцию Array.indexOf() внутри одного цикла, который эффективно будет вложенным циклом в отношении производительности.)

Это предполагает, что никакие два элемента в data не имеют одинакового свойства id.

Ответ 8

Вы можете сделать это с помощью 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]);

Попробуйте этот пример в jsFiddle.