2016-07-27 3 views
2

Я ищу способ изменить порядок массива на набор последовательных фиксированных значений. Например:JAVASCRIPT переупорядочивает массив по группам последовательных значений

У меня есть массив элементов:

items = [ 
    {id: 1, name: "Test 1", group: 1}, 
    {id: 2, name: "Test 2", group: 2}, 
    {id: 3, name: "Test 3", group: 2}, 
    {id: 4, name: "Test 4", group: 2}, 
    {id: 5, name: "Test 5", group: 1}, 
    {id: 6, name: "Test 6", group: 2}, 
    {id: 7, name: "Test 7", group: 1}, 
    {id: 8, name: "Test 8", group: 3}, 
    {id: 9, name: "Test 9", group: 1}, 
    {id: 10, name: "Test 10", group: 3} 
]; 

Я знаю также, что у меня есть три группы:

groups = [ 
    {id: 1, name: "Group 1"}, 
    {id: 2, name: "Group 2"}, 
    {id: 3, name: "Group 3"} 
]; 

И то, что я хочу сделать похож на что :

new_array = [ 
{id: 1, name: "Test 1", group: 1}, 
{id: 2, name: "Test 2", group: 2}, 
{id: 8, name: "Test 8", group: 3}, 
{id: 5, name: "Test 5", group: 1}, 
{id: 3, name: "Test 3", group: 2}, 
{id: 10, name: "Test 10", group: 3} 
{id: 7, name: "Test 7", group: 1}, 
{id: 4, name: "Test 4", group: 2}, 
{id: 9, name: "Test 9", group: 1}, 
{id: 6, name: "Test 6", group: 2}, 
]; 

Я хочу, чтобы отсортировать мой массив, «группа» 3 пунктов следующего порядка группы 1, 2, 3

Знаете ли вы умный способ сделать это? Я не знаю, с чего начать ...

+3

http://stackoverflow.com/questions/1129216/sort-array-of-objects-by-string-property-value-in-javascript является отправной точкой – epascarello

+0

@epascarello Я не понимаю, как этот вопрос поможет. – smarx

+0

@smarx действительно? Это кажется откровенно по теме .. Сортировка массивов объектов по суб-свойствам? Вы можете попробовать один и тот же метод сравнения для реализации алгоритма сортировки. – dckuehn

ответ

0

Для достаточно малых наборов данных, вы можете пойти с простым алгоритмом, такими как эта. Просто имейте в виду, что findIndex() и splice() - довольно дорогостоящие методы.

var items = [ 
 
     {id: 1, name: "Test 1", group: 1}, 
 
     {id: 2, name: "Test 2", group: 2}, 
 
     {id: 3, name: "Test 3", group: 2}, 
 
     {id: 4, name: "Test 4", group: 2}, 
 
     {id: 5, name: "Test 5", group: 1}, 
 
     {id: 6, name: "Test 6", group: 2}, 
 
     {id: 7, name: "Test 7", group: 1}, 
 
     {id: 8, name: "Test 8", group: 3}, 
 
     {id: 9, name: "Test 9", group: 1}, 
 
     {id: 10, name: "Test 10", group: 3} 
 
    ], 
 
    groups = [ 
 
     {id: 1, name: "Group 1"}, 
 
     {id: 2, name: "Group 2"}, 
 
     {id: 3, name: "Group 3"} 
 
    ]; 
 

 
var res = [], i, n; 
 

 
for(n = 0; items.length; n = (n + 1) % groups.length) { 
 
    if((i = items.findIndex(function(v) { return v.group == groups[n].id; })) != -1) { 
 
    res.push(items.splice(i, 1)); 
 
    } 
 
} 
 

 
// displaying formatted output 
 
console.log(JSON.stringify(res).split('}],').join('}],\n'));

0
var items = [ 
    {id: 1, name: "Test 1", group: 1}, 
    {id: 2, name: "Test 2", group: 2}, 
    {id: 3, name: "Test 3", group: 2}, 
    {id: 4, name: "Test 4", group: 2}, 
    {id: 5, name: "Test 5", group: 1}, 
    {id: 6, name: "Test 6", group: 2}, 
    {id: 7, name: "Test 7", group: 1}, 
    {id: 8, name: "Test 8", group: 3}, 
    {id: 9, name: "Test 9", group: 1}, 
    {id: 10, name: "Test 10", group: 3} 
]; 

// grouped will map group IDs to arrays of items 
// e.g. { '1': [ { id: 1, name: 'Test 1', group: 1 }, ... ], '2': ... } 
var grouped = {}; 

for (var i = 0; i < items.length; i++) { 
    var item = items[i]; 
    if (grouped[item.group] === undefined) { 
    grouped[item.group] = []; 
    } 
    grouped[item.group].push(item); 
} 

// definition of groups and their order 
var groups = [ 
    {id: 1, name: "Group 1"}, 
    {id: 2, name: "Group 2"}, 
    {id: 3, name: "Group 3"} 
]; 

// we'll start with the first group 
var groupIndex = 0; 

var output = []; 
for (var i = 0; i < items.length; i++) { 
    // skip any empty groups 
    while (grouped[groups[groupIndex].id].length === 0) { 
    groupIndex = (groupIndex + 1) % groups.length; 
    } 

    // pull the first item from the group and add it to our output 
    output.push(grouped[groups[groupIndex].id].shift()); 

    // move to the next group 
    groupIndex = (groupIndex + 1) % groups.length; 
} 

console.log(output); 
// Output: 
// [ { id: 1, name: 'Test 1', group: 1 }, 
// { id: 2, name: 'Test 2', group: 2 }, 
// { id: 8, name: 'Test 8', group: 3 }, 
// { id: 5, name: 'Test 5', group: 1 }, 
// { id: 3, name: 'Test 3', group: 2 }, 
// { id: 10, name: 'Test 10', group: 3 }, 
// { id: 7, name: 'Test 7', group: 1 }, 
// { id: 4, name: 'Test 4', group: 2 }, 
// { id: 9, name: 'Test 9', group: 1 }, 
// { id: 6, name: 'Test 6', group: 2 } ] 

EDIT

Вот альтернативное решение, используя lodash:

var grouped = _.groupBy(items, function (item) { return item.group; }); 
var groupLists = _.map(groups, function (group) { return grouped[group.id]; }); 
var output = _.filter(_.flatten(_.zip.apply(null, groupLists))); 
console.log(output); 
0

Решение с использованием подчеркивания для группировки.

  • Шаг 1: группа
  • Шаг 2: сортировать каждую группу по идентификатору
  • Шаг 3: поп из каждой группы, чтобы результирующий массив

Пример:

I» ve перетасовал ваш items, чтобы подтвердить, что группировка находится в порядке возрастания id, даже если не в источнике.

items = [ 
 
    {id: 1, name: "Test 1", group: 1}, 
 
    {id: 3, name: "Test 3", group: 2}, 
 
    {id: 4, name: "Test 4", group: 2}, 
 
    {id: 6, name: "Test 6", group: 2}, 
 
    {id: 2, name: "Test 2", group: 2}, 
 
    {id: 9, name: "Test 9", group: 1}, 
 
    {id: 10, name: "Test 10", group: 3}, 
 
    {id: 5, name: "Test 5", group: 1}, 
 
    {id: 7, name: "Test 7", group: 1}, 
 
    {id: 8, name: "Test 8", group: 3} 
 
]; 
 
var grouped = _.groupBy(items, function(obj) { 
 
    return obj.group; 
 
}); 
 

 
for (var index in grouped) { 
 
    var attr = grouped[index]; 
 
    attr.sort(function(a, b) { 
 
    return (a.id - b.id); 
 
    }); 
 
} 
 
var res = []; 
 
for (var i = 0; i < items.length; i++) { 
 
    for (var index in grouped) { 
 
    if (grouped[index].length > 0) { 
 
     res.push(grouped[index].shift()); 
 
    }; 
 

 
    } 
 
} 
 
console.log(res);
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.3/underscore-min.js"></script>

0
//init positions by groupId 
var positionsByGroupId = {}, numGroups = groups.length; 
groups.forEach(({id}, i) => { positionsByGroupId[id] = i }); 

//compute the position of each item in the sorted Array. 
//compose the item with the computed value we are sorting by 
items.map(item => { 
    return { 
     value: item, 
     //get value and update the index for this group 
     //since we use this value only for sorting, it doesn't matter 
     //that it is actually offset by one row 
     position: positionsByGroupId[ item.group ] += numGroups 
    } 
}) 
//sort by the position, to get the right order 
.sort((a, b) => a.position - b.position) 
//return the ordered items 
.map(obj => obj.value); 

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

Но мы можем сделать это, фактически не группируя элементы, потому что мы можем вычислить их индекс на выходе как col + row * numColumns. Поскольку столбцы могут быть не полностью заполнены, эта позиция может не соответствовать фактическому индексу вывода, но мы все равно можем использовать их для определения порядка элементов.

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

Edit: Я не уверен, что это кастрированный баран совсем понятно, но большая часть этого кода является сортировка по вычисленной стоимости, так что если вы используете какой-LIB, который поддерживает, что, как lodash, например, вы можете сократить его:

var positionsByGroupId = {}, numGroups = groups.length; 
_.forEach(groups, ({id}, i) => { positionsByGroupId[id] = i }); 
_.sortBy(items, item => positionsByGroupId[ item.group ] += numGroups); 
Смежные вопросы