【问题标题】:Convert flat structure to hierarchical with sort by attribute将平面结构转换为按属性排序的分层结构
【发布时间】:2023-03-09 09:57:01
【问题描述】:

我对@9​​87654321@ 有同样的问题,实际上它是从 url 解决的。但我想让结果按特定字段排序(例如:序列字段)。

let items = [
    {
        id: 1,
        parentId: null,
        name: 'A',
        sequence: 1
    },
    {
        id: 4,
        parentId: 1,
        name: 'A-2',
        sequence: 2
    },
    {
        id: 5,
        parentId: 1,
        name: 'A-1',
        sequence: 1
    },
    {
        id: 2,
        parentId: null,
        name: 'B',
        sequence: 2
    }
];

结果:

[
    {
        id: 1,
        parentId: null,
        name: 'A',
        sequence: 1,
        children: [
            {
                id: 5,
                parentId: 1,
                name: 'A-1',
                sequence: 1
            },
            {
                id: 4,
                parentId: 1,
                name: 'A-2',
                sequence: 2
            },
        ]
    },
    {
        id: 2,
        parentId: null,
        name: 'B',
        sequence: 2
    }
];

是否有任何我应该使用的自定义代码,所以我可以让结果也按序列字段排序?

【问题讨论】:

  • 您忘记添加已有的 JavaScript 代码。请阅读How to Ask,而不是edit 并添加minimal reproducible example
  • 到目前为止您尝试过什么?您介意添加您的code 尝试来解决您的问题吗?
  • @RokoC.Buljan js 代码与我提到的 URL 上的解决方案相同。我需要按特定字段排序...

标签: javascript


【解决方案1】:

/**
 * Sort an array of objects by property
 * @param {Array} arr Array of Objects
 * @param {String} p The property to sort
 * @param {boolean} desc Set to true for descend. sort
 */
const sortBy = (arr, p, desc) => arr.sort((a, b) => {
  if (desc) [a, b] = [b, a];
  const isNum = typeof b[p] === 'number';
  return (isNum ? Number(a[p]) - b[p] : String(a[p]).localeCompare(b[p]));
});

/**
 * Convert Linear Array to Tree Array
 * @param {Array} list to convert
 * @param {String} sort the property to sort
 */
const treefy = (list, sort) => {
  const map = list.reduce((m, li, i) => {
    m[li.id] = i;
    li.children = [];
    return m;
  }, {});
  return list.reduce((root, li) => {
    const arr = li.parentId ? list[map[li.parentId]].children : root;
    arr.push(li);
    if (sort) sortBy(arr, sort);
    return root;
  }, []);
}

// Use like:
const items = [
  {id:1, parentId:null, name:"B", sequence:2},
  {id:4, parentId:1, name:"A-2", sequence:2},
  {id:5, parentId:1, name:"A-1", sequence:1},
  {id:2, parentId:null, name:"A", sequence:1}
];
const tree = treefy(items, "sequence");
console.log(tree)

【讨论】:

  • 谢谢... sortBy 非常完美!使用额外的 typeof 检查...
【解决方案2】:

您可以映射出 id,然后遍历映射,以便将引用添加到某些元素的子元素中:

let items = [{
    id: 1,
    parentId: null,
    name: 'A',
    sequence: 1
  },
  {
    id: 4,
    parentId: 1,
    name: 'A-2',
    sequence: 2
  },
  {
    id: 5,
    parentId: 1,
    name: 'A-1',
    sequence: 1
  },
  {
    id: 2,
    parentId: null,
    name: 'B',
    sequence: 2
  }
];

function tree(array) {
  let mapping = {};

  array.forEach(i => {
    mapping[i.id] = i; // Maps out the ids
  });

  array = [];

  for (let id in mapping) {
    let child = mapping[id];
    let {
      parentId
    } = child;
    if (parentId) { // If there is a parent
      let parent = mapping[parentId];
      if (!parent.children) parent.children = [child];
      else parent.children.push(child);
    }
  }

  for (let id in mapping) { // Add to the items ONLY the parents
    if (!mapping[id].parentId) array.push(mapping[id]);
  }

  return array.sort((a, b) => a.id - b.id); // Make sure that the ids are in sequential order
}

console.log(tree(items));

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多