2016-02-21 3 views
1

У меня есть 2 массивыСортировка массива объектов, основанный на другой массив идентификаторов

a = [2,3,1,4] 
b = [{id: 1}, {id: 2}, {id: 3}, {id: 4}] 

Как получить b сортируют на основе a? Мой желаемый результат будет

c = [{id: 2}, {id: 3}, {id: 1}, {id: 4}] 

Я бы предпочел использовать Ramda или обычный JS.

+1

Действительно ли реальные объекты 'b' содержат что-либо иное, чем просто' id'? – georg

ответ

2

Ramda действительно сияет для этих проблем.

Если размер данных невелик, мы можем использовать простую функцию reduce и вспомогательный помощник indexOf.

// match id of object to required index and insert 
var sortInsert = function (acc, cur) { 
    var toIdx = R.indexOf(cur.id, a); 
    acc[toIdx] = cur; 
    return acc; 
}; 

// point-free sort function created 
var sort = R.reduce(sortInsert, []); 

// execute it now, or later as required 
sort(b); 
// [ { id: 2 }, { id: 3 }, { id: 1 }, { id: 4 } ] 

Это хорошо работает для небольших (ISH) наборов данных, но indexOf операции на каждой итерации за счет сокращения неэффективно для больших наборов данных.

Мы можем исправить это, зайдя на проблему с другой стороны, давайте сможем использовать groupBy, чтобы сгруппировать наши объекты по их идентификатору, создав таким образом поиск по словарю (намного лучше!). Затем мы можем просто map по необходимым индексам и преобразовать их в соответствующий объект в этой позиции.

А вот решение с использованием этого подхода:

var groupById = R.groupBy(R.prop('id'), b); 

var sort = R.map(function (id) { 
    return groupById[id][0]; 
}); 

sort(a); 
// [ { id: 2 }, { id: 3 }, { id: 1 }, { id: 4 } ] 

Наконец, это еще одно решение, которое является очень емким:

R.sortBy(R.pipe(R.prop('id'), R.indexOf(R.__, a)))(b); 
// [ { id: 2 }, { id: 3 }, { id: 1 }, { id: 4 } ] 

Я люблю то, как вы можете сочинить функции с поведением и отделить алгоритм от данных, на которых он действует, используя Ramda. Вы получаете очень читаемый и простой в обслуживании код.

+0

Не могли бы вы сделать 'sortInsert' чистую функцию? :) – davidchambers

0

Вы можете просто создать c основаны от a, никогда не используя b:

var a = [2,3,1,4]; 
var c = []; 

for(var i = 0; i < a.length; i++){ 

    c.append({id:a[i]); 

} 

Надеется, что это помогает!

1

Это решение использует Array#sort со вспомогательным объектом c для индексов.

{ 
    "1": 2, 
    "2": 0, 
    "3": 1, 
    "4": 3 
} 

var a = [2, 3, 1, 4], 
 
    b = [{ id: 1 }, { id: 2 }, { id: 3 }, { id: 4 }], 
 
    c = a.reduce(function (r, a, i) { 
 
     r[a] = i; 
 
     return r; 
 
    }, {}); 
 

 
b.sort(function (x, y) { 
 
    return c[x.id] - c[y.id]; 
 
}); 
 

 
document.write('<pre>' + JSON.stringify(b, 0, 4) + '</pre>');

Для больших объектов, я предлагаю использовать Sorting with map.

1

Или может быть проще

b.sort(function(obj1,obj2){ 
    return a.indexOf(obj1.id) > a.indexOf(obj2.id) 
}); 
0

Plain JavaScript, используя некоторые методы (стандарт ES2015) Array

var a = [2,3,1,4]; 
 
var b = [{id: 1}, {id: 2}, {id: 3}, {id: 4}]; 
 
var c = []; 
 

 
a.forEach(el => c.push(b.find(e => e.id == el))); 
 

 
document.write(JSON.stringify(c, 0, 2));

2

Это довольно простая задача:

var sortOrder = [2,3,1,4], 
    items  = [{id: 1}, {id: 2}, {id: 3}, {id: 4}]; 

items.sort(function(a, b){ 
    return sortOrder.indexOf(a.id) - sortOrder.indexOf(b.id); 
}); 
1

Использование Ramda, вы должны сопоставить объекты в б их индекс с помощью mapObjIndexed функции, а затем искать значение в . Вы можете попробовать here.

var a = [2,3,1,4]; 
var b = [{id: 1}, {id: 2}, {id: 3}, {id: 4}] 
R.find(R.propEq('id', a[0]), b) 
R.values(R.mapObjIndexed( (num, key, obj) => R.find(R.propEq('id', a[key]), b) , b)) 
Смежные вопросы