请教大家一个比较麻烦的排序问题?

[
    {
        "value": "4.7.5.1xxxx"
    },
    {
        "value": "4.7.5.2xxxx"
    },
    {
        "value": "4.7.5.3xxxx"
    },
    {
        "value": "4.4.1.1xxxx"
    },
    {
        "value": "4.7.2.1xxxx"
    },
    {
        "value": "5.1.1xxxx"
    },
    {
        "value": "5.1.2xxxx"
    },
    {
        "value": "如何xxxx"
    },
    {
        "value": "如何xxxx"
    },
    {
        "value": "如何xxxx"
    },
    {
        "value": "如何xxxx"
    },
    {
        "value": "如何xxxx"
    },
    {
        "value": "如何xxxx"
    },
    {
        "value": "2.1.1.1xxxx"
    },
    {
        "value": "2.1.1.2xxxx"
    },
    {
        "value": "2.1.2.1xxxx"
    },
    {
        "value": "2.1.2.2xxxx"
    },
    {
        "value": "2.1.3.1xxxx"
    },
    {
        "value": "2.1.3.2xxxx"
    },
    {
        "value": "2.2.1.1xxxx"
    },
    {
        "value": "2.2.1.2xxxx"
    },
    {
        "value": "2.3.1.1xxxx"
    },
    {
        "value": "2.3.1.2xxxx"
    },
    {
        "value": "2.3.2.1xxxx"
    },
    {
        "value": "2.3.2.2xxxx"
    },
    {
        "value": "2.4.1.1xxxx"
    },
    {
        "value": "2.4.1.2xxxx"
    },
    {
        "value": "3.2.1.1xxxx"
    },
    {
        "value": "3.2.1.2xxxx"
    }
]

上面的数组对象我想排序成如何 xxxx 这些数据都在最前面,其它前面有序号的按照2.1.1.1 2.1.1.2 ... 3.2.1.1 3.2.1.2 这样依次往下排列,请问如何实现呢?

阅读 2.3k
5 个回答

自定义 sort(),一个不成熟的实现:

const arr = [
    // ...
];

console.log(
    arr.sort((a, b) => {
        if (a.value.startsWith("如何")) {
            return -1;
        }
        if (b.value.startsWith("如何")) {
            return 1;
        }
        return a.value < b.value ? -1 : 1;
    })
);

08-30 更新:我确实没有考虑到多位数版本号的情况,原回答依旧保留,参考 @Mannix 的回答做一个补充:

arr.sort(({ value: a }, { value: b }) => {
    if (a.startsWith("如何")) {
        return -1;
    }
    if (b.startsWith("如何")) {
        return 1;
    }

    const regA = /\.?\d+/y;
    const regB = /\.?\d+/y;
    let res: number;
    let rA: string | undefined;
    let rB: string | undefined;
    do {
        rA = regA.exec(a)?.[0];
        rB = regB.exec(b)?.[0];
        res = Number(rA) - Number(rB);
    } while (res === 0 && rA != null);

    return res;
});

考虑可能存在两位数的情况,如 '10.1xxxx',所以按数值大小比较比较保险,其次再按照层数从少到多排列,遇到非数字当成 0 处理即可排到前面,所以不用对非数字开头的数据做特别处理

const arr = [
  { value: '1.1.1.2xxxx' },
  { value: '10.1xxxx' },
  { value: '1.1.1.1xxxx' },
  { value: '如何xxxx' },
  { value: '1.2.2.1xxxx' },
  { value: '1.1.2.1xxxx' },
  { value: '1.2.2.2xxxx' },
  { value: '1.2.1.1xxxx' },
  { value: '1.1.2.2xxxx' },
  { value: '2.1.1.1xxxx' },
  { value: '1.2xxxx' },
  { value: '2.1.1xxxx' },
  { value: '10.1xxxx' },
  { value: '如何xxxx' },
];
arr.sort(({ value: a }, { value: b }) => {
  const aRE = /\.?(\d+)/y;
  const bRE = /\.?(\d+)/y;
  let aM, bM, res;
  do {
    aM = aRE.exec(a)?.[1] | 0;
    bM = bRE.exec(b)?.[1] | 0;
    res = aM - bM;
  } while (!res && aM);
  return res;
});
[
  { value: '如何xxxx' },
  { value: '如何xxxx' },
  { value: '1.1.1.1xxxx' },
  { value: '1.1.1.2xxxx' },
  { value: '1.1.2.1xxxx' },
  { value: '1.1.2.2xxxx' },
  { value: '1.2xxxx' },
  { value: '1.2.1.1xxxx' },
  { value: '1.2.2.1xxxx' },
  { value: '1.2.2.2xxxx' },
  { value: '2.1.1xxxx' },
  { value: '2.1.1.1xxxx' },
  { value: '10.1xxxx' },
  { value: '10.1xxxx' }
]
arr.sort((a,b) => {
     // 首字符不为数字直接判断为所谓“如何xxx”的情况
  if(/^\D/.test(a.value)) return -1
  if(/^\D/.test(b.value)) return 1;

  // 以下则为数字开头的情况
  // 将数字提取出来便于比较判断
  var reg = /(\d\.?)+/
  var v1 = a.value.match(reg)[0].split('.')
  var v2 = b.value.match(reg)[0].split('.')
  // 兼容数字不等长的情况
  // 保证v1是最长的数组
  var isReverse = v1.length < v2.length;
  if(isReverse) [v1, v2] = [v2, v1]
  // 遍历数组比较数值
  for(var i = 0;i<v1.length;i++) {
    var res = v1[i] - (v2[i]||0);
    // 比较结果为0继续比较下一数字,不为0则返回排序结果
    // 当b的数字比a的长时,由于上面交换了两个数字数组,故而结果也需反转
    if(res) return isReverse ? ~res+1 : res;
  }
    return 0
})
function sortArr(arr) {
  const arr1 = arr.filter(x => x.value.startsWith('如何'))
  const arr2 = arr.filter(x => !x.value.startsWith('如何'))
  arr2.sort((a, b) => {
    let a1 = a.value.split('.')
    let a2 = b.value.split('.')
    let i = 0
    while(true) {
      let s1 = a1[i]
      let s2 = a2[i]
      i++
      if (s1 === undefined || s2 === undefined) {
        return a1.length - a2.length
      }
      if (s1 === s2) {
        continue
      }
      return s1 - s2
    } 
  })
  return [...arr1, ...arr2]
}

遍历一遍把带如何的摘出来放一个数组,其他的在一个数组,分别排序然后合并

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题