面试代码题之——实现拍平数组并排序

133 阅读3分钟

题目描述

咱们就开门见山,直接来看题目~

补充以下代码,实现拍平数组并排序功能

// [1, 2, [4, 3], [[5, 6], 7]] 得到  [1,2,3,4,5,6,7,....]
const flatAndSort = (arr) => {
  // .....
}

思路

既然是拍平并排序,咱们就分开两步来,先把原数组进行拍平,然后再对拍平数组排序

那么如何拍平呢

我的思路就是另外开辟一个数组,然后遍历数组所有元素,若该元素不是数组,则直接添加到新数组里,若该元素是数组,则继续递归拍平该元素.....

代码如下:(这里我用了数组的reduce方法来遍历数组)

const flattenArr = (arr: any[]): number[] => {
    //返回的是最后拍平的数组
    return arr.reduce((acc: number[], item) => {
        // 如果当前元素是数组,递归拍平
        if (Array.isArray(item)) {
            acc.push(...flattenArr(item))
        }else {
            // 否则直接添加到结果数组
            acc.push(item)
        }
        return acc
    }, [])
}

那么如何排序呢

最简单的当然就是使用数组的sort方法

flattenedArr.sort((a, b) => a - b)

当然你也可以自己实现一个排序算法,例如冒泡排序,快速排序,这里就不列举了。

既然刚好用到了数组的sort方法,那就带大家复习一下数组的sort方法

默认情况下

默认情况下,sort 方法会将数组元素转换为字符串,然后按照 字典序(Unicode 码点顺序) 进行排序。

const arr = [10, 5, 20, 1];
arr.sort();
console.log(arr); // 输出: [1, 10, 20, 5]

默认的字典序排序可能会导致数字排序不符合预期(如 10 排在 5 前面)

但是默认排序规则适合字符串排序

const arr = ['banana', 'apple', 'cherry'];
arr.sort();
console.log(arr); // 输出: ['apple', 'banana', 'cherry']


自定义排序规则

sort 方法可以接受一个 比较函数(compare function) 作为参数,用于定义排序规则。

比较函数的规则:
  • 比较函数接受两个参数 ab,分别表示当前比较的两个元素。
  • 返回值决定排序顺序:
    • 如果返回值 小于 0,则将 a 排在 b 前面。
    • 如果返回值 等于 0,则 ab 的相对位置不变。
    • 如果返回值 大于 0,则将 b 排在 a 前面。
示例:数字升序排序
const arr = [10, 5, 20, 1];
arr.sort((a, b) => a - b);
console.log(arr); // 输出: [1, 5, 10, 20]
对对象数组排序
const users = [
  { name: 'Alice', age: 25 },
  { name: 'Bob', age: 30 },
  { name: 'Charlie', age: 20 },
];

users.sort((a, b) => a.age - b.age);
console.log(users);
// 输出:
// [
//   { name: 'Charlie', age: 20 },
//   { name: 'Alice', age: 25 },
//   { name: 'Bob', age: 30 }
// ]

从 ES2019(ECMAScript 10)开始,sort 方法是 稳定排序 的。这意味着如果两个元素相等,它们的相对顺序在排序前后保持不变。

注意sort 方法会直接修改原数组。如果需要保留原数组,可以先复制一份再排序

最终代码

const flattenArr = (arr: any[]): number[] => {
    return arr.reduce((acc: number[], item) => {
        // 如果当前元素是数组,递归拍平
        if (Array.isArray(item)) {
            acc.push(...flattenArr(item))
        }else {
            // 否则直接添加到结果数组
            acc.push(item)
        }
        return acc
    }, [])
}

const flattenAndSortArr = (arr: any[]): number[] => {
    const flattenedArr = flattenArr(arr)
    return flattenedArr.sort((a, b) => a - b)
}

const nestedArray = [1, 2, [4, 3], [[5, 6], 7]];
const flattenAndSortArrResult = flattenAndSortArr(nestedArray);
console.log(flattenAndSortArrResult);

扩展思考

上面的方法并没有考虑非数字元素,如果数组中有非数字元素会影响最终的排序结果

解决方法一:过滤非数字元素

 function flattenArray(arr: any[]): number[] {
   return arr.reduce((acc: number[], item) => {
     if (Array.isArray(item)) {
       acc.push(...flattenArray(item));
     } else if (typeof item === 'number') {
       //确保元素是数字元素才添加
       acc.push(item);
     }
     return acc;
   }, []);
}

解决方法二:自定义排序规则

 function flattenAndSort(arr: any[], compareFn?: (a: number, b: number) => number): number[] {
   const flattened = flattenArray(arr);
   return flattened.sort(compareFn || ((a, b) => a - b));
}

至于这个排序规则函数就要根据实际情况自己来编写了