【问题标题】:sort array of objects recursively for all children为所有孩子递归地排序对象数组
【发布时间】:2020-06-19 21:09:14
【问题描述】:

我有一个对象数组,其中包含许多级别的嵌套子项,我需要通过比较同一级别项的两个属性来对其进行排序。数组有多个嵌套项,所以我带来了这个需要排序的最小数组。

每个项目至少有 3 个属性(路径、标题和上一个),并且一些项目可能具有与子项目相似的项目。

// unsorted array
const original = [
  {
    "path": "path3",
    "title": "title3",
    "previous": "title2",
    "children": [
      { "path": "child31", "title": "child31", "previous": null },
      { "path": "child32", "title": "child32", "previous": "child31" },
      { "path": "child33", "title": "child33", "previous": "child32" }
    ]
  },
  {
    "path": "path1",
    "title": "title1",
    "previous": null,
    "children": [
      { "path": "child11", "title": "child11", "previous": null },
      { "path": "child13", "title": "child13", "previous": "child12" },
      { "path": "child14", "title": "child14", "previous": "child13" },
      { "path": "child12", "title": "child12", "previous": "child11",
        "children": [
          { "path": "child123", "title": "child123", "previous": "child122" },
          { "path": "child121", "title": "child121", "previous": null },
          { "path": "child122", "title": "child122", "previous": "child121",
            "children": [
              { "path": "child1221", "title": "child1221", "previous": null, 
                "children": [
                  {
                    "path": "child12211",
                    "title": "child12211",
                    "previous": null
                  },
                  {
                    "path": "child1222",
                    "title": "child1222",
                    "previous": "child1221"
                  }
                ]
              },
              {
                "path": "child1224",
                "title": "child1224",
                "previous": "child1223"
              },
              {
                "path": "child1222",
                "title": "child1222",
                "previous": "child1221"
              },
              {
                "path": "child1223",
                "title": "child1223",
                "previous": "child1222",
                "children": [
                  {
                    "path": "child12231",
                    "title": "child12231",
                    "previous": null
                  }
                ]
              }
            ]
          }
      ]}
    ]
  },
  { "path": "path2", "title": "title2", "previous": "title1" }
];

我需要通过比较同一父项中项目的先前值和标题值来对该数组进行排序。如果 previous 为 null 任何项目,那将是该父项中的第一个项目,对于下一个项目,previous 将是它的前一个兄弟的标题,依此类推。

这是我的排序功能:

const sortNav = items => {
  let result = [...items].sort(function (a, b) {
    if(a.title === b.previous || a.previous === null) {
      return -1;
    } 
    if (a.previous === b.title || b.previous === null) {
      return 1;
    }
    return 0;
  })

  for(let i = 0; i < items.length; i++) {
    if (items[i].children && items[i].children.length) {
      items[i].children = sortNav(items[i].children);
    }
  }
  return result;
};

我正在使用这样的功能

const sorted = sortNav(original);

original array

original sorted array

【问题讨论】:

  • 您应该在问题中包含您的初始数据以及您想要的结果
  • @Gershom 初始数据在 pastebin,我没有预期的数据,将用这个更新问题
  • 您发现哪些条目在排序时优先级错误?
  • @MadanBhandari 如果您能提供一个更小的初始数据集及其预期结果可能会有所帮助,以便我们更简洁地了解您想要什么
  • @Tibebes.M 内部(第 3 个或更多)子级排序错误

标签: javascript node.js


【解决方案1】:

我会说你需要定义一个排序函数并像这样递归地传递它

var origArray = ['a','b','c',['a','b','c']];

function SortRecursive(a, b){
 let aArray = Array.isArray(a);
 let bArray = Array.isArray(b);

 if(aArray == bArray){
  if(aArray){
   a.sort(SortRecursive);
   b.sort(SortRecursive);
   return a[0] > b[0] ? -1 : a[0] < b[0] ? 1 : 0;
  } else {
   return a > b ? -1 : a < b ? 1 : 0;
  }
 } else {
  return aArray && !bArray ? -1 : !aArray && bArray ? 1 : 0;
 }
}

origArray.sort(SortRecursive);

这可能与您想要的数据排序方式不完全一样,因为我们没有得到您的数据的示例,但您应该能够看到我对子数组做了什么。

另一方面,这也会对同一个数组进行多次排序,所以应该想出一种方法来识别已经排序的子数组。

【讨论】:

  • 我已经添加了示例输入和输出数组。
  • 你的问题是你无法对对象进行排序它只是不起作用你可以对对象数组排序而不是对象的内容
  • 这是一个对象数组
【解决方案2】:

问题是您正在对 items 对象的子对象进行排序,但从函数返回 result 对象。因此,对列表进行排序BEFORE

const sortNav = items => {

  for(let i = 0; i < items.length; i++) {
    if (items[i].children && items[i].children.length) {
      console.log("calling sort for children of ", items[i].title, items[i].children)
      items[i].children = sortNav(items[i].children);
    }
  }
 
  let result = [...items].sort(function (a, b) {
    if(a.title === b.previous || a.previous === null) {
      console.log("comparing ...", a.pathTitle, " > ", b.pathTitle)
      return -1;
    } 
    if (a.previous === b.title || b.previous === null) {
      console.log("compare ...", a.pathTitle, " < ", b.pathTitle)
      return 1;
    }
    return 0;
  })

  console.log("sorted =>", result);
  
  return result;
};

这应该照顾没有被排序的孩子。但是根据您的示例数据,我还注意到对于以下两个元素的情况,sort 函数返回 0,这意味着它周围的元素永远不会正确排序。

[{
  "pathTitle": "set-up-standard-payments.md",
  "title": "Set up standard payments",
  "previous": "credit and debit card payments"
},
{
  "pathTitle": "configure-payments",
  "title": "Configure Payments",
  "previous": "Add capabilities",
  "children": [
    {
      "pathTitle": "alternative-payment-methods.md",
      "title": "Payment Methods",
      "previous": null
    }
  ]
}]

鉴于您有点/有点想像链表一样重新排序列表,我建议改用以下函数:-

const reoderList = (items) => {
	var result = [];
  for(let i = 0; i < items.length; i++) {
    if (items[i].children && items[i].children.length) {
      items[i].children = reorderList(items[i].children);
    }
  }
    
  items.forEach(item => {
    if(item.previous === null) {
        result = [item, ...result];
    }
    else {
      var index = result.findIndex(r => r.title === item.previous);
      if(index > -1) {
        result.splice(index+1,0,item);
      }
      else {
        result = [...result,item];
      }
    }
  });
  return result;
};

编辑:从预期的输出中,您还需要之前的 === null 对象始终显示在顶部。这可能需要对结果列表进行第二次传递以确保这一点。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2010-11-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-12-30
    • 2011-02-12
    • 2020-11-13
    • 2021-11-22
    相关资源
    最近更新 更多