繁体   English   中英

排序类别和子类别的数组

[英]Sorting an array of categories and subcategories

假设我们有一个对象数组,其中每个对象代表一个类别或一个子类别,如下所示:

var data = [
    {type: "parent-category", order: 1, categoryId: 1},
    {type: "parent-category", order: 2, categoryId: 2},
    {type: "child-category", order: 1, categoryId: 3, parentCategoryId: 1},
    {type: "child-category", order: 2, categoryId: 4, parentCategoryId: 1},
    {type: "child-category", order: 2, categoryId: 5, parentCategoryId: 2},
    {type: "child-category", order: 1, categoryId: 6, parentCategoryId: 2}
];

该数组代表一个具有两个类别的示例,其中每个类别还具有两个子类别。

现在,我面临着以某种自定义方式对数组进行排序的问题。 您可以注意到,每个对象内的order属性与对象在其层次结构中的位置(或顺序)有关。 类别与子类别之间的关系由属性parentCategoryId定义。

我需要使用之前的数据数组作为示例的预期排序应为以下形式:

var data = [
    {type: "parent-category", order: 1, categoryId: 1},
    {type: "child-category", order: 1, categoryId: 3, parentCategoryId: 1},
    {type: "child-category", order: 2, categoryId: 4, parentCategoryId: 1},
    {type: "parent-category", order: 2, categoryId: 2},
    {type: "child-category", order: 1, categoryId: 6, parentCategoryId: 2},
    {type: "child-category", order: 2, categoryId: 5, parentCategoryId: 2}   
];

我当前解决此问题的方法是基于创建数字映射,并在以下条件下分析属性的值:

  • 对于类型为parent-category的对象,我们分配categoryId * 1000的值。
  • 对于具有子类别类的对象,我们分配(parentCategoryId * 1000) + order

下一个排序实现中显示了此逻辑:

 let data = [ {type: "parent-category", order: 1, categoryId: 1}, {type: "parent-category", order: 2, categoryId: 2}, {type: "child-category", order: 1, categoryId: 3, parentCategoryId: 1}, {type: "child-category", order: 2, categoryId: 4, parentCategoryId: 1}, {type: "child-category", order: 2, categoryId: 5, parentCategoryId: 2}, {type: "child-category", order: 1, categoryId: 6, parentCategoryId: 2} ]; let orderedData = data.sort((a, b) => { var aCat = (a.type == "parent-category") ? a.categoryId : a.parentCategoryId; var aOrder = (a.type == "parent-category") ? 0 : a.order; var bCat = (b.type == "parent-category") ? b.categoryId : b.parentCategoryId; var bOrder = (b.type == "parent-category") ? 0 : b.order; return (aCat * 1000 + aOrder) - (bCat * 1000 + bOrder); }); console.log(orderedData); 

但是,我忽略了以前的实现有效的事实,我的问题是是否存在解决此问题的更好方法或替代方法。 我不喜欢依赖于数字的映射,因为,例如,以前的实现对子类别的数量(在这种情况下为999 )引入了限制,我可以在每个类别下正确地进行排序。 谢谢!

如果性能不是问题,我宁愿使用更分步的方法:

 /* ORIGINAL DATA */ const data = [ {type: "parent-category", order: 1, categoryId: 1}, {type: "parent-category", order: 2, categoryId: 2}, {type: "child-category", order: 1, categoryId: 3, parentCategoryId: 1}, {type: "child-category", order: 2, categoryId: 4, parentCategoryId: 1}, {type: "child-category", order: 2, categoryId: 5, parentCategoryId: 2}, {type: "child-category", order: 1, categoryId: 6, parentCategoryId: 2} ]; const sorted = []; const byOrder = (a, b) => a.order - b.order; // Get and sort parents first const parents = data.filter(obj => obj.type === 'parent-category'); parents.sort(byOrder); // Push to resulting array by parent order parents.forEach(obj => { sorted.push(obj); // Get and sort corresponding children objs const children = data.filter(o => o.parentCategoryId === obj.categoryId); children.sort(byOrder); // Push the objs into resulting array together sorted.push.apply(sorted, children); }); console.log(sorted); 

与复杂的排序逻辑相比,此方法涉及更多步骤,但简单明了,并且易于理解。

仅将外部库用于一种功能是过大的。

使用Array#filter Array#sort和Array#map的简单性能解决方案

 var data=[{type:"parent-category",order:1,categoryId:1},{type:"parent-category",order:2,categoryId:2},{type:"child-category",order:1,categoryId:3,parentCategoryId:1},{type:"child-category",order:2,categoryId:4,parentCategoryId:1},{type:"child-category",order:2,categoryId:5,parentCategoryId:2},{type:"child-category",order:1,categoryId:6,parentCategoryId:2}] let res = data .filter(({type}) => type === "parent-category") .sort((a,b) => a.order - b.order) .reduce((acc, curr) =>{ const children = data .filter(({parentCategoryId}) => parentCategoryId === curr.categoryId) .sort((a,b) => a.order - b.order); acc.push(curr, ...children); return acc; }, []); console.log(res); 

为简便起见 ,请使用lodash#orderBy


如果您不喜欢lodash ,则可以sort定义自己的特定函数

我还不太了解您的排序标准,但是,例如,

function sort_categories(cat1,cat2) {
  if (cat1["order"] < cat2["order"])
    return -1;
  if (cat1["order"] > cat2["order"])
    return 1;
  return 0;
}

data.sort(sort_categories);

只会按订单排序。

有关返回值的详细信息,请在此处查看

如果提供了compareFunction,则根据比较函数的返回值对所有未定义的数组元素进行排序(所有未定义的元素均排序到数组的末尾,而无需调用compareFunction)。 如果a和b是要比较的两个元素,则:

  • 如果compareFunction(a,b)小于0,则将a排序为小于b的索引(即,a在前)。

  • 如果compareFunction(a,b)返回0,则a和b彼此相对不变,但对所有不同元素进行排序。 注意:ECMAscript标准不保证此行为,因此并非所有浏览器(例如,至少可追溯到2003年的Mozilla版本)都遵守此规定。

  • 如果compareFunction(a,b)大于0,则将b排序为小于a的索引(即b首先出现)。

  • 当给定一对特定的元素a和b作为其两个参数时,compareFunction(a,b)必须始终返回相同的值。 如果返回不一致的结果,则排序顺序不确定。

这将起作用。 您首先对categoryId排序,然后通过运行forEach函数进行数学运算。

 var data = [ {type: "parent-category", order: 1, categoryId: 1}, {type: "parent-category", order: 2, categoryId: 2}, {type: "child-category", order: 1, categoryId: 3, parentCategoryId: 1}, {type: "child-category", order: 2, categoryId: 4, parentCategoryId: 1}, {type: "child-category", order: 2, categoryId: 5, parentCategoryId: 2}, {type: "child-category", order: 1, categoryId: 6, parentCategoryId: 2} ]; data.sort( function(a, b){ return a.categoryId - b.categoryId; }).forEach( function(itm){ itm.categoryId = itm.categoryId * 1000; if( itm.parentCategoryId){ itm.parentCategoryId = itm.parentCategoryId * 1000 + itm.order } }); console.log(data); 

或以ES6方式...

let orderedData = data.sort( (a, b) => {
       return a.categoryId - b.categoryId;
    }).forEach( itm => {
        itm.categoryId = itm.categoryId * 1000;
        if( itm.parentCategoryId){
            itm.parentCategoryId = itm.parentCategoryId * 1000 + itm.order
        }
    });

基于@kemicofa的答案。 刚刚更改以支持两个以上级别

function iterative(categories, parentCategory, level = 0) {
  return categories
    .filter((category) => parentCategory ? category.parent === parentCategory : !category.parent)
    .map(category => {
       category.level = level;
       return category;
    })
    .sort((a,b) => a.name.localeCompare(b.name))
    .reduce((acc, curr) =>{
      const children = iterative(categories, curr.id, level+1)

      acc.push(curr, ...children);
      return acc;
    }, [])
  ;
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM