【问题标题】:Specific reverse sort of objects array对象数组的特定反向排序
【发布时间】:2023-02-21 23:22:54
【问题描述】:

我有一个对象数组:

const arr = [
{
  name: Exhibit A
}, 
{
  name: Exhibit A1
}, 
{
  name: Exhibit A2
}, 
{
  name: Exhibit B
}, 
{
  name: Exhibit C
}, 
{
  name: Exhibit C1
},  
{
  name: Exhibit C2
}, 
{
  name: Exhibit C3
}, 
]

我需要对它进行反向排序,但没有编号的展品应该首先在其组中。

像那样:

const result = [
{
  name: Exhibit C
}, 
{
  name: Exhibit C3
}, 
}, 
{
  name: Exhibit C2
}, 
}, 
{
  name: Exhibit C1
},
{
  name: Exhibit B
}, 
{
  name: Exhibit A
}, 
{
  name: Exhibit A2
}, 
{
  name: Exhibit A1
}
]

const result = [...arr].sort((a, b) => {???})

简单的 localeCompare 没有像我想要的那样工作,所以我需要找到另一种方法。

有任何想法吗?

【问题讨论】:

  • 你试过什么了?

标签: javascript arrays sorting


【解决方案1】:

您可以创建适合您需要的自定义比较器。 请参阅Here 了解它的外观。

在您的情况下,比较器可能由比较器名称的拆分组成,然后首先比较字母,然后比较数字。 “无字母”被视为比任何数字都“更好”。

【讨论】:

    【解决方案2】:

    const arr = [
       { name: "Exhibit A"  }, 
       { name: "Exhibit A1" }, 
       { name: "Exhibit A2" }, 
       { name: "Exhibit B"  }, 
       { name: "Exhibit C"  }, 
       { name: "Exhibit C1" },  
       { name: "Exhibit C2" }, 
       { name: "Exhibit C3" }, 
    ];
    
    function cmp( a, b ) { return a < b ? -1 : a > b ? 1 : 0; }
    
    // Array of [ 0:orig, 1:base_name, 2:has_number, 3:number ]
    const extended = arr.map(
       _ => {
          const matches = _.name.match( /^Exhibit (D+)(d*)$/ );
          return [ _, matches[1], matches[2] === "", parseInt( matches[2] ) ];
       }
    );
    
    extended.sort(
       ( a, b ) =>
          (  cmp( b[1], a[1] )  // By descending base name, or
          || cmp( b[2], a[2] )  // by descending has digits, or
          || cmp( b[3], a[3] )  // by descending digits.
          )
    );
    
    const sorted = extended.map( _ => _[0] );
    
    console.log( sorted );

    扩展数组可以避免对相同的输入进行多次昂贵的计算(正则表达式匹配)。这种方法称为Schwartzian transform 或 decorate-sort-undecorate。

    【讨论】:

      【解决方案3】:

      您可以添加一些 9 并降序排序。

      const
          asc = (a, b) => a.localeCompare(b),
          desc = (a, b) => (b + '999999999').localeCompare(a + '999999999'),
          array = [{ name: 'Exhibit A' }, { name: 'Exhibit A1' }, { name: 'Exhibit A2' }, { name: 'Exhibit B' }, { name: 'Exhibit C' }, { name: 'Exhibit C1' }, { name: 'Exhibit C2' }, { name: 'Exhibit C3' }];
      
      array.sort((a, b) => desc(a.name, b.name));
      console.log(array);
      
      array.sort((a, b) => asc(a.name, b.name));
      console.log(array);
      .as-console-wrapper { max-height: 100% !important; top: 0; }

      【讨论】:

      • @BenStephens,对,我看到了问题;-)
      【解决方案4】:

      这本来可以更聪明,但它有效并且比其他“Schwartzian 变换”更具可读性

      var collator = new Intl.Collator([], {
        numeric: true
      });
      const newArr = arr.slice(0).map(item => item.name.replace(/d/g).length === item.name.length ? { "name": item.name + "ç" } : item);
      
      newArr.sort((a, b) => collator.compare(b.name, a.name))
        .forEach(item => item.name = item.name.replace("ç", ""));
      
      console.log(newArr)
      <script>
        const arr = [{
            name: "Exhibit A"
          },
          {
            name: "Exhibit A2"
          },
          {
            name: "Exhibit B"
          },
          {
            name: "Exhibit A1"
          },
          {
            name: "Exhibit C"
          },
          {
            name: "Exhibit C1"
          },
          {
            name: "Exhibit C2"
          },
          {
            name: "Exhibit C3"
          },
        ]
      </script>

      【讨论】:

        【解决方案5】:

        最有趣(写作,而不是阅读)并且可能是最糟糕的方法(从数字中拆分文本,用文本构建元组,用数字构建元组,检查元组中的顺序直到找到一个,如果有一个空字符串逆序):

        const data = [
        {name: 'Exhibit A'},
        {name: 'Exhibit A1'},
        {name: 'Exhibit B2'},
        {name: 'Exhibit A2'},
        {name: 'Exhibit B'},
        {name: 'Exhibit B1'},
        {name: 'Exhibit C1'},
        {name: 'Exhibit C'},
        {name: 'Exhibit A3'},
        {name: 'Exhibit C2'},
        ]
        
        const sorter = (...args) => args.map( a => a.name.match(/^(.*?)(d*)$/).slice(1,3) )
         .reduce( (g,e) => e.map( (s,i) => g[i] = [...(g[i]??[]), s]), [])
         .reduce( (v,es) => v || (es.includes('') && es.reverse(), es[1].localeCompare(es[0])), 0)
        
        console.log(data.sort( sorter) )

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2023-04-09
          • 1970-01-01
          • 2019-11-21
          • 1970-01-01
          • 2020-05-21
          • 1970-01-01
          • 2011-06-02
          • 2021-02-11
          相关资源
          最近更新 更多