FrankKai / FrankKai.github.io

FE blog
https://frankkai.github.io/
362 stars 39 forks source link

深入理解Array.prototype.sort() #229

Open FrankKai opened 4 years ago

FrankKai commented 4 years ago

初识sort()

举例说明"将元素转换为字符串":

sort() demo

const months = ['March', 'Jan', 'Feb', 'Dec'];
months.sort();
console.log(months);
// ["Dec", "Feb", "Jan", "March"]
const array1 = [1, 30, 4, 21, 100000];
array1.sort();
console.log(array1);
// [1, 100000, 21, 30, 4]

sort() 语法

arr.sort([compareFunction])

比较函数compareFunction

sort() 升降序规则(重点)

比较函数伪代码:

function compare(a, b) {
  if (a is less than b by some ordering criterion) {
    return -1;
  }
  if (a is greater than b by the ordering criterion) {
    return 1;
  }
  // a must be equal to b
  return 0;
}

为了比较数字而不是字符串,可以对a,b做减法运算

// 升序排列
function compareNumbers(a, b) {
  return a - b;
}
// 降序排列
function compareNumbers(a, b) {
  return b - a;
}

sort函数可以直接运行匿名函数:

var numbers = [4, 2, 5, 1, 3];
numbers.sort(function(a, b) {
  return a - b;
});
console.log(numbers);

// [1, 2, 3, 4, 5]

箭头函数写法:

let numbers = [4, 2, 5, 1, 3];
numbers.sort((a, b) => a - b);
console.log(numbers);

// [1, 2, 3, 4, 5]

根据对象的一个属性排序:

var items = [
  { name: 'Edward', value: 21 },
  { name: 'Sharpe', value: 37 },
  { name: 'And', value: 45 },
  { name: 'The', value: -12 },
  { name: 'Magnetic', value: 13 },
  { name: 'Zeros', value: 37 }
];

// sort by value
items.sort(function (a, b) {
  return a.value - b.value;
});

// sort by name
items.sort(function(a, b) {
  var nameA = a.name.toUpperCase(); // ignore upper and lowercase
  var nameB = b.name.toUpperCase(); // ignore upper and lowercase
  if (nameA < nameB) {
    return -1;
  }
  if (nameA > nameB) {
    return 1;
  }

  // names must be equal
  return 0;
});

创建、展示和排序数组

var stringArray = ['Blue', 'Humpback', 'Beluga'];
var numericStringArray = ['80', '9', '700'];
var numberArray = [40, 1, 5, 200];
var mixedNumericArray = ['80', '9', '700', 40, 1, 5, 200];

function compareNumbers(a, b) {
  return a - b;
}

console.log('stringArray:', stringArray.join());
console.log('Sorted:', stringArray.sort());

console.log('numberArray:', numberArray.join());
console.log('Sorted without a compare function:', numberArray.sort());
console.log('Sorted with compareNumbers:', numberArray.sort(compareNumbers));

console.log('numericStringArray:', numericStringArray.join());
console.log('Sorted without a compare function:', numericStringArray.sort());
console.log('Sorted with compareNumbers:', numericStringArray.sort(compareNumbers));

console.log('mixedNumericArray:', mixedNumericArray.join());
console.log('Sorted without a compare function:', mixedNumericArray.sort());
console.log('Sorted with compareNumbers:', mixedNumericArray.sort(compareNumbers));
stringArray: Blue,Humpback,Beluga
Sorted: Beluga,Blue,Humpback

numberArray: 40,1,5,200
Sorted without a compare function: 1,200,40,5
Sorted with compareNumbers: 1,5,40,200

numericStringArray: 80,9,700
Sorted without a compare function: 700,80,9
Sorted with compareNumbers: 9,80,700

mixedNumericArray: 80,9,700,40,1,5,200
Sorted without a compare function: 1,200,40,5,700,80,9
Sorted with compareNumbers: 1,5,9,40,80,200,700

排序non-ASCII字符

对于类似e, é, è, a, ä这样的字符来说,可以通过String.localeCompare进行排序。

var items = ['réservé', 'premier', 'communiqué', 'café', 'adieu', 'éclair'];
items.sort(function (a, b) {
  return a.localeCompare(b);
});

// items is ['adieu', 'café', 'communiqué', 'éclair', 'premier', 'réservé']

map()结合sort()一起使用

// the array to be sorted
var list = ['Delta', 'alpha', 'CHARLIE', 'bravo'];

// temporary array holds objects with position and sort-value
var mapped = list.map(function(el, i) {
  return { index: i, value: el.toLowerCase() };
})

// sorting the mapped array containing the reduced values
mapped.sort(function(a, b) {
  if (a.value > b.value) {
    return 1;
  }
  if (a.value < b.value) {
    return -1;
  }
  return 0;
});

// container for the resulting order
var result = mapped.map(function(el){
  return list[el.index];
});
// ["alpha", "bravo", "CHARLIE", "Delta"]
[
  {
    "index": 1,
    "value": "alpha"
  },
  {
    "index": 3,
    "value": "bravo"
  },
  {
    "index": 2,
    "value": "charlie"
  },
  {
    "index": 0,
    "value": "delta"
  }
]

条件改为if (a.value < b.value) { return 1; } if (a.value > b.value) { return -1; }时,变为降序。

[
  {
    "index": 0,
    "value": "delta"
  },
  {
    "index": 2,
    "value": "charlie"
  },
  {
    "index": 3,
    "value": "bravo"
  },
  {
    "index": 1,
    "value": "alpha"
  }
]

也可以加一个meta,改为:

// the array to be sorted
var list = ['Delta', 'alpha', 'CHARLIE', 'bravo'];

// temporary array holds objects with position and sort-value
var mapped = list.map(function(el, i) {
  return { index: i, value: el.toLowerCase(), meta: el, };
})

// sorting the mapped array containing the reduced values
mapped.sort(function(a, b) {
  if (a.value > b.value) {
    return 1;
  }
  if (a.value < b.value) {
    return -1;
  }
  return 0;
});
var result = mapped.map(function(el){
  return el.meta
});
// ["alpha", "bravo", "CHARLIE", "Delta"]

对象根据value给key排序

有一个高级用法:对象根据value给key排序

const items = {
   foo: 2,
   bar: 1,
   baz: 3,
};
// 降序
const sortKeys = Object.keys(items).sort((a,b)=>items[b]-items[a])
// ["baz", "foo", "bar"]

leetcode347.前K个高频元素可以通过这个特性做出来:

var topKFrequent = function (nums, k) {
    /**
     * 解法1:统计排序法
     */
    const obj = {};
    for (let num of nums) {
        if (!obj[num]) {
            obj[num] = 1
        } else {
            obj[num]++;
        };
    }
    // {1:3, 2:2, 3:1} => [1, 2, 3]
    // {8:2, 3:5, 2:4} => [3, 2, 8]
    const descKeys = Object.keys(obj).sort((a, b) => obj[b] - obj[a]);
    const result = descKeys.splice(0, k);
    return result;
};

题解位于:https://github.com/FrankKai/leetcode-js/blob/master/347.Top_K_Frequent_Elements.js

总结

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort