【问题标题】:Sorting an array alphabetically, but with exceptions按字母顺序对数组进行排序,但有例外
【发布时间】:2016-07-19 03:10:22
【问题描述】:

我有以下数组结构

[{
  name: "Mobile Uploads"
}, {
  name: "Profile Pictures"
}, {
  name: "Reports"
}, {
  name: "Instagram Photos"
}, {
  name: "Facebook"
}, {
  name: "My Account"
}, {
  name: "Twitter"
}]

我想对数组重新排序,使其按以下顺序排列:Profile PicturesMobile UploadsInstagram Photos,之后的对象按字母顺序排列。

【问题讨论】:

  • 与其考虑移动元素,不如考虑按照您想要的顺序创建一个包含元素的新数组。您可以使用sortmapfilter 等例程来执行此操作。这就是我们通常在 JS 中这样做的方式。顺便说一句,您在这里使用了“有效”一词。我在JS问题中看到了很多。从技术上讲,这意味着“快速性能”。这就是你的意思,或者你真的意思是,通常情况下,“以一种易于阅读和写作的方式”?
  • 嘿@Brown,所以您正在寻找 2 个订单:个人资料图片、手机上传、Instagram 照片和 Instagram 照片、手机上传、个人资料图片
  • @torazaburo sort 实际上确实在数组中移动元素。 mapfilter 将创建新数组,但 sort 就地运行。

标签: javascript arrays


【解决方案1】:

您要做的是创建一个包含排序异常的对象。然后你可以编写一个自定义的sort() 函数来解决你的异常。

var list = [{
  name: "Date"
}, {
  name: "Mobile Uploads"
}, {
  name: "Profile Pictures"
}, {
  name: "Fig"
}, {
  name: "Instagram Photos"
}, {
  name: "Cherry"
}, {
  name: "Apple"
}, {
  name: "Banana"
}];

var exceptions = {
  "Profile Pictures": 1,
  "Mobile Uploads": 2,
  "Instagram Photos": 3
}

list.sort(function(a, b) {
  if (exceptions[a.name] && exceptions[b.name]) {
    //if both items are exceptions
    return exceptions[a.name] - exceptions[b.name];
  } else if (exceptions[a.name]) {
    //only `a` is in exceptions, sort it to front
    return -1;
  } else if (exceptions[b.name]) {
    //only `b` is in exceptions, sort it to back
    return 1;
  } else {
    //no exceptions to account for, return alphabetic sort
    return a.name.localeCompare(b.name);
  }
});

console.log(list);

【讨论】:

  • 看起来比我的方法更干净,逻辑更容易遵循 +1
【解决方案2】:
    var algo = [{
        name: "Mobile Uploads"
     },
     { 
        name: "Zeta"
     },
     {
        name: "Beta"
     },
     {
        name: "Alfa"
     },
     { 
        name: "Profile Pictures"
     },
     {
        name: "Instagram Photos"
     }]

var compare = function(a,b){
    var weight = {"Profile Pictures":1, "Mobile Uploads":2, "Instagram Photos":3}
    ,   nameA = a.name
    ,   weightA = weight[nameA] || 100
    ,   nameB = b.name
    ,   weightB = weight[nameB] || 100

    if(weightA != weightB){
        return weightA - weightB;
    }else{
        return nameA > nameB;
    }

}

console.log(algo.sort(compare));

这个想法是分配权重来管理排序。

【讨论】:

【解决方案3】:

我相信最好的方法就是使用自定义 sort 完成所有操作。排序回调函数有两个参数,第一个数组元素和它正在比较的第二个数组元素。然后,您可以在回调主体中使用您希望的任何逻辑来决定返回什么。如果返回 -1,则这意味着第一个元素应该在第二个元素之前。如果返回 1,则这意味着第二个元素应该在第一个元素之前。如果返回 0,这意味着两个元素是相等的,因此应该保持并排排列,这样在排序过程中就不会将其他元素插入到中间。

要按字母顺序排序,您可以使用<><=>= 运算符将两个字符串相互比较。然后结果将是布尔值 true 或 false,因此您希望返回 -11,具体取决于您想要升序还是降序 - 就您比较它们的方式而言。如果您认为您将在数组中遇到重复项并希望实现速度稍快一些,除非您正在处理大数据,否则您也可以检查是否相等并返回 0

要为字母排序添加例外,我建议为第一个元素创建一个数字表示,然后为第二个元素创建另一个数字表示。使用负数表示异常之间的排序,其中数字越小表示它应该越接近数组的开头。然后对其他所有内容使用 0 表示它不是例外。然后最后使用简单的 if 语句检查是否存在异常。在没有例外的情况下,按字母排序。否则我们有一个例外,应该按照较小的数字表示的顺序进行排序。

    

var inputArray = [{
  name: "Mobile Uploads"
}, {
  name: "Profile Pictures"
}, {
  name: "Reports"
}, {
  name: "Instagram Photos"
}, {
  name: "Facebook"
}, {
  name: "My Account"
}, {
  name: "Twitter"
}];

var sortedArray = inputArray.slice(0);//copy of the original array as sort is destructive.
sortedArray.sort(function(a,b){
    var aIndex = 0, bIndex = 0;
    switch(a.name)
    {
        case "Profile Pictures":
            aIndex = -3;
            break;
        case "Mobile Uploads":
            aIndex = -2;
            break;
        case "Instagram Photos":
            aIndex = -1;
            break;
    }
    switch(b.name)
    {
        case "Profile Pictures":
            bIndex = -3;
            break;
        case "Mobile Uploads":
            bIndex = -2;
            break;
        case "Instagram Photos":
            bIndex = -1;
            break;
    }
   if(aIndex < 0 || bIndex < 0)//Check if either element being compared needs special treatment
   {
       //in the case of two exceptions, we want the smallest one to be sorted first
       //otherwise in the case of one exception the other element would be a 0
       return aIndex < bIndex ? -1 : 1;//ascending
   }
   else
   {
       //otherwise just sort in alpabetical order comparing strings with the less than operator
       return a.name < b.name ? -1 : 1;//ascending
   }
});

//Before
console.log('Before:');
console.log(inputArray.map(function(v){
    return v.name;
}).join(', '));//Mobile Uploads, Profile Pictures, Reports, Instagram Photos, Facebook, My Account, Twitter

//After
console.log('After:');
console.log(sortedArray.map(function(v){
    return v.name;
}).join(', '));//Profile Pictures, Mobile Uploads, Instagram Photos, Facebook, My Account, Reports, Twitter

【讨论】:

  • 返回零是一种浪费,除非数组会遇到重复,即使这样,数组也会在不考虑重复项的情况下正常排序。在 OP 的问题中,看起来他或她正在尝试构建某种导航栏,该导航栏一开始就没有重复项,因此更快的方法是不考虑重复项。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2010-12-12
  • 1970-01-01
  • 2019-06-15
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多