Упорядочение массива с иерархией по счету, возможно, с использованием lodash. (nodejs)

1

Я немного застрял в этом: у меня есть массив объектов, упорядоченных по иерархии (parent_id), что-то вроде:

let myArray = [
 { id: 1, parent_id: null, score: 20, type: 1 },
 { id: 12, parent_id: 1, score: 25, type: 2 },
 { id: 23, parent_id: 12, score: 55, type: 3 },
 { id: 35, parent_id: 12, score: 25, type: 3 },
 { id: 10, parent_id: null, score: 75, type: 1 },
 { id: 25, parent_id: 10, score: 15, type: 2 },
 { id: 100, parent_id: 25, score: 88, type: 3 }
]

Теперь я хотел бы сохранить порядок иерархии, но также упорядочить элементы по результату, чтобы получить что-то вроде этого:

let expected = [
 { id: 10, parent_id: null, score: 75, type: 1 },
 { id: 25, parent_id: 10, score: 15, type: 2 },
 { id: 100, parent_id: 25, score: 88, type: 3 },
 { id: 1, parent_id: null, score: 20, type: 1 },
 { id: 12, parent_id: 1, score: 25, type: 2 },
 { id: 23, parent_id: 12, score: 55, type: 3 },
 { id: 35, parent_id: 12, score: 25, type: 3 },
]

Я пишу довольно неэффективный код с вложенным foreach который почти работает, но и не совсем. Мне было интересно, есть ли более аккуратное решение. (довольно уверен, что есть, но слишком умный для меня). Также в моем коде я передаю атрибут type, но в идеале я бы не использовал его для сортировки.

Примечание. Эти данные являются всего лишь примером, реальный массив больше и число детей для каждого родителя меняется.

Поскольку мои объяснения не велики, мы можем думать об иерархии таким образом type:1type:2 страны type:2type:3 государства type:3 → Город

Так что мне нужно заказать по desc как это

- Country
  - State
    - City 
    - City
  - State
    - City
 - Country and so on...

Спасибо всем, кто готов принести мне руку,

  • 1
    Я запутался, как вы поддерживаете parent_id, сохраняя при этом порядок очков?
  • 0
    почему id 10 перед 1?
Показать ещё 6 комментариев
Теги:
lodash

2 ответа

2
Лучший ответ

Один вид не работает из-за отношения родительских детей, которое не соблюдается при сортировке данных.

Этот подход работает в трех частях:

  1. Сортировка данных по score, так как следующее дерево создается в порядке вставки.
  2. Постройте дерево с данными отношениями.
  3. Пройдите по дереву и верните отсортированные плоские данные.

var data = [{ id: 1, parent_id: null, score: 20, type: 1 }, { id: 12, parent_id: 1, score: 25, type: 2 }, { id: 23, parent_id: 12, score: 55, type: 3 }, { id: 35, parent_id: 12, score: 25, type: 3 }, { id: 10, parent_id: null, score: 75, type: 1 }, { id: 25, parent_id: 10, score: 15, type: 2 }, { id: 100, parent_id: 25, score: 88, type: 3 }]
        .sort(function (a, b) { return b.score - a.score; }),
    tree = function (data, root) {
        var r = [], o = {};
        data.forEach(function (a) {
            o[a.id] = { data: a, children: o[a.id] && o[a.id].children };
            if (a.parent_id === root) {
                r.push(o[a.id]);
            } else {
                o[a.parent_id] = o[a.parent_id] || {};
                o[a.parent_id].children = o[a.parent_id].children || [];
                o[a.parent_id].children.push(o[a.id]);
            }
        });
        return r;
    }(data, null),                               // null is the root value of parent_id
    sorted = tree.reduce(function traverse(r, a) {
        return r.concat(a.data, (a.children || []).reduce(traverse, []));
    }, [])

console.log(sorted);
console.log(tree);
.as-console-wrapper { max-height: 100% !important; top: 0; }
  • 0
    вау, спасибо По какой-то причине он не хочет работать с моим реальным набором данных, но я полагаю, вы очень сильно меня направили в правильном направлении
  • 0
    возможно, id или parent_id имеют другое имя.
Показать ещё 6 комментариев
1

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

let arr = [
  {country: 'USA', state:'Washington', city:'Washington DC'},
  {country: 'USA', state:'Washington', city:'Boston'},
  {country: 'USA', state:'California', city:'San Diego'},
  {country: 'Brazil', state:'North', city:'C'},
  {country: 'Brazil', state:'North', city:'B'},
  {country: 'Brazil', state:'South', city:'A'},
  {country: 'Turkey', state:'East', city:'f'},
  {country: 'Turkey', state:'East', city:'e'},
  {country: 'Turkey', state:'West', city:'d'},
];

let expected = [
  {country: 'Brazil', state:'North', city:'B'},
  {country: 'Brazil', state:'North', city:'C'},
  {country: 'Brazil', state:'South', city:'A'},
  {country: 'Turkey', state:'East', city:'e'},
  {country: 'Turkey', state:'East', city:'f'},
  {country: 'Turkey', state:'West', city:'d'},
  {country: 'USA', state:'California', city:'San Diego'},
  {country: 'USA', state:'Washington', city:'Boston'},
  {country: 'USA', state:'Washington', city:'Washington DC'},
];

const sortByCountry = arr => {
  return arr.sort((city1,city2) => city1.country > city2.country);
};

const sortByState = arr =>
  arr.sort(
    (city1,city2) => {
      // Don't compare when countries differ.
      if (city1.country !== city2.country) return 0;
      return city1.state > city2.state;
    }
  );

const sortByCity = arr =>
  arr.sort(
    (city1,city2) => {
      // Don't compare when countries or states differ.
      if (city1.country !== city2.country) return 0;
      if (city1.state !== city2.state) return 0;
      return city1.city > city2.city;
    }
  );

let result = sortByCity(sortByState(sortByCountry(arr)));

console.log('------expected-----');
console.log(expected);
console.log('------result-----');
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Ещё вопросы

Сообщество Overcoder
Наверх
Меню