【问题标题】:How to change sorting order when sorting mixed items with String.localeCompare?使用 String.localeCompare 对混合项目进行排序时如何更改排序顺序?
【发布时间】:2018-07-12 16:15:26
【问题描述】:

假设我们有一个包含混合 name 值(数字、西里尔文、英文)的对象数组:

(如果代码不适合你,把undefined改成'ru',也会改变排序结构)

let ascending = true

var items = [
  {name: 'c', value: ''}, 
  {name: 'b', value: ''}, 
  {name: 'a', value: ''}, 
  {name: 'д', value: ''}, 
  {name: 'в', value: ''}, 
  {name: '41', value: ''}, 
  {name: 'а', value: ''}, 
  {name: 'б', value: ''}, 
  {name: '0', value: ''}, 
  {name: '31', value: ''}, 
  {name: '4', value: ''}, 
  {name: 'г', value: ''}
]

items.sort(function (a, b) {
  // ascending order
  if (ascending) {
    return a.name.localeCompare(b.name, undefined, { numeric: true });
  }
  // descending order
  else {
    return b.name.localeCompare(a.name, undefined, { numeric: true });
  }
})

console.log(items);

当前结果

我得到具有以下结构的升序排序数组:

  • 数字(升序)
  • 英语(升序)
  • 非英语(升序)

ascending = true时的结果:

{name: "0", value: ""}
{name: "31", value: ""}
{name: "4", value: ""}
{name: "41", value: ""}
{name: "a", value: ""}
{name: "b", value: ""}
{name: "c", value: ""}
{name: "а", value: ""}
{name: "б", value: ""}
{name: "в", value: ""}
{name: "г", value: ""}
{name: "д", value: ""}

想要的结果

当ascending = false 并保留结构时,我需要它能够以降序对数组进行排序:

  • 数字(降序)
  • 英语(降序)
  • 非英语(降序)

ascending = false时需要的结果:

{name: "41", value: ""}
{name: "31", value: ""}
{name: "4", value: ""}
{name: "0", value: ""}    
{name: "c", value: ""}
{name: "b", value: ""}
{name: "a", value: ""}
{name: "д", value: ""}
{name: "г", value: ""}
{name: "в", value: ""}
{name: "б", value: ""}
{name: "а", value: ""}

问题

当我更改 ascending = false 并将 b.name 的位置更改为 a.name 时,它只会将整个数组倒置,而不是翻转其“类别”(数字、英语、西里尔字母)中的值。

我不确定如何正确执行此操作。我的意思是,反转数组会反转值,所以我应该在它翻转数组后重新构造数组“类别”吗?可能是这样的:

  • 获取所有编号为isNaN()的对象并将它们移到顶部

  • 然后在[0] 处获取仅包含a-z 的项目并将它们移动到数字“类别”下方

  • 其他一切都停留在底部

【问题讨论】:

  • 在.sort()末尾追加.reverse()
  • 这意味着如果你想将项目分成单独的类别,你根本不能使用localeCompare
  • @Adelin 在数组上调用 reverse 与反转排序没有什么不同(就像切换 ascending 已经做的那样)
  • @Bergi 嗯,你知道任何其他方法来对这样一个混合数组进行排序,同时保留所需的结构吗?
  • @Un1 获取每一项的“类别”,然后先比较类别。

标签: javascript arrays sorting


【解决方案1】:

如果您有识别数字、英文和非英文字符串的机制,您可以使用以下想法:

var items = [
  { name: "c", value: "" },
  { name: "b", value: "" },
  { name: "a", value: "" },
  { name: "д", value: "" },
  { name: "в", value: "" },
  { name: "41", value: "" },
  { name: "а", value: "" },
  { name: "б", value: "" },
  { name: "0", value: "" },
  { name: "31", value: "" },
  { name: "4", value: "" },
  { name: "г", value: "" }
];

function sortFunctionMaker(ascending) {
  function isNumber(str) {
    return Number.isNaN(Number(str)) === false;
  }

  function isEnglish(str) {
    return /^[a-zA-Z]+$/.test(str);
  }

  return function(a, b) {
    var aw, bw;

    if (isNumber(a.name)) {
      aw = 1;
    } else if (isEnglish(a.name)) {
      aw = 2;
    } else {
      aw = 3;
    }
    if (isNumber(b.name)) {
      bw = 1;
    } else if (isEnglish(b.name)) {
      bw = 2;
    } else {
      bw = 3;
    }

    if (aw !== bw) {
      // a and b belong to different categories
      // no further comparison is needed
      return aw - bw;
    } else if (aw === 1) {
      // both are numbers
      // sort mathematically
      return (ascending ? 1 : -1) * (a.name - b.name);
    } else {
      // both are english or otherwise
      // sort using localeCompare
      return (ascending ? 1 : -1) * a.name.localeCompare(b.name);
    }
  }
}

items.sort(sortFunctionMaker(true));
console.log("Ascending");
items.forEach(function(item) {
  console.log(item.name);
});

items.sort(sortFunctionMaker(false));
console.log("Descending");
items.forEach(function(item) {
  console.log(item.name);
});
console.groupEnd();

【讨论】:

    【解决方案2】:

    在我的解决方案中:

    1. 首先将数据分为3类(数组):
      "nums"、"en"、"nonen";
    2. 对它们中的每一个进行排序;
    3. 以正确的顺序将它们放在一个数组中
      var ascending = true;
      var english = /^[A-Za-z]/;
      var items = [
        {name: 'c', value: ''}, 
        {name: 'b', value: ''}, 
        {name: 'a', value: ''}, 
        {name: 'д', value: ''}, 
        {name: 'в', value: ''}, 
        {name: '41', value: ''}, 
        {name: 'а', value: ''}, 
        {name: 'б', value: ''}, 
        {name: '0', value: ''}, 
        {name: '31', value: ''}, 
        {name: '4', value: ''}, 
        {name: 'г', value: ''}
      ];
      
      var groups = items.reduce((acc,currentVal)=>{
        if(!isNaN(parseInt(currentVal.name))) {
          acc[0].push(currentVal); // first array will contain nums
        } else if(english.test(currentVal.name)){
          acc[1].push(currentVal); //second will contain english chars
        } else {
          acc[2].push(currentVal) // last will contain rest chars
        }
        return acc;
        
      },[[],[],[]]);
      
      var sortFunc = function(a,b){
          return a.name.localeCompare(b.name, undefined, { numeric: true });
      }
      var groupSorted = [];
      groups.forEach(group => groupSorted.push(...ascending?group.sort(sortFunc):group.sort(sortFunc).reverse()));
      console.log(groupSorted);

    【讨论】:

      【解决方案3】:

      之后我设法通过将已排序的“类别”移动到所需位置来重组翻转数组:

      • 数字(降序)
      • 英语(降序)
      • 非英语(降序)

      let ascending = false
      
      var items = [
        {name: 'c', value: ''}, 
        {name: 'b', value: ''}, 
        {name: 'a', value: ''}, 
        {name: 'д', value: ''}, 
        {name: 'в', value: ''}, 
        {name: '41', value: ''}, 
        {name: 'а', value: ''}, 
        {name: 'б', value: ''}, 
        {name: '0', value: ''}, 
        {name: '31', value: ''}, 
        {name: '4', value: ''}, 
        {name: 'г', value: ''}
      ]
      
      items.sort(function (a, b) {
        // ascending order
        if (ascending) {
          return a.name.localeCompare(b.name, undefined, { numeric: true });
        }
        // descending order
        else {
          return b.name.localeCompare(a.name, undefined, { numeric: true });
        }
      })
      
      
      if (ascending == false) {
        var englishAlphabet = "abcdefghijklmnopqrstuvwxyz"
        let nums = []
        let english = []
        let other = []
      
        items.forEach(element => {
          if (isNaN(element.name[0]) == false) {
            nums.push(element)
          }
          else if (englishAlphabet.includes(element.name[0].toLowerCase())) {
            english.push(element)
          }
          else {
            other.push(element)
          }
        });
      
        let restructuredItems = nums.concat(english).concat(other)
      
        console.log('BEFORE RESTRUCTURING', items);
        console.log('AFTER RESTRUCTURING: ', restructuredItems);
      }

      【讨论】:

        猜你喜欢
        • 2022-01-13
        • 1970-01-01
        • 2021-05-08
        • 1970-01-01
        • 2019-02-22
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多