杨__羊羊
函数任意排序这是解决您的问题的另一种方法。假设我们有一些fruits并且任意的order我们希望对它们进行排序 -const fruits = // 0 1 2 3 4 [ "apple", "banana", "cherry", "orange", "peach" ] const order = [ 1, 3, 2, 0, 4 ]我们希望能够写出这样的东西 -fruits.sort(sortByIndex(fruits, order))console.log(fruits)// [ "banana", "orange", "cherry", "apple", "peach" ]// 1 3 2 0 4我们希望有一个Comparison模块来处理我们的排序代码 -const { empty, map } = Comparison const sortByIndex = (values = [], indexes = []) => map(empty, x => indexes.indexOf(values.indexOf(x)))现在我们只需要实施Comparison-const Comparison = { empty: (a, b) => a < b ? -1 : a > b ? 1 : 0 , map: (m, f) => (a, b) => m(f(a), f(b)) }const { empty, map } = Comparisonconst sortByIndex = (values = [], indexes = []) => map(empty, x => indexes.indexOf(values.indexOf(x)))const fruits = [ "apple", "banana", "cherry", "orange", "peach" ] // 0 1 2 3 4 const order = [ 1, 3, 2, 0, 4 ]console.log(fruits)// [ "apple", "banana", "cherry", "orange", "peach" ]console.log(fruits.sort(sortByIndex(fruits, order)))// [ "banana", "orange", "cherry", "apple", "peach" ]为什么是模块?实现一个Comparison模块意味着我们有一个整洁的地方来存储所有的比较逻辑。我们可以轻松实现其他有用的功能,例如reverse现在concat-const Comparison = { // ... , concat: (m, n) => (a, b) => Ordered.concat(m(a, b), n(a, b)) , reverse: (m) => (a, b) => m(b, a) }const Ordered = { empty: 0 , concat: (a, b) => a === 0 ? b : a }现在我们可以轻松地对复杂的排序逻辑进行建模 -const sortByName = map(empty, x => x.name)const sortByAge = map(empty, x => x.age)const data = [ { name: 'Alicia', age: 10 } , { name: 'Alice', age: 15 } , { name: 'Alice', age: 10 } , { name: 'Alice', age: 16 } ]排序依据name然后排序依据age-data.sort(concat(sortByName, sortByAge))// [ { name: 'Alice', age: 10 }// , { name: 'Alice', age: 15 }// , { name: 'Alice', age: 16 }// , { name: 'Alicia', age: 10 }// ]排序依据age然后排序依据name-data.sort(concat(sortByAge, sortByName))// [ { name: 'Alice', age: 10 }// , { name: 'Alicia', age: 10 }// , { name: 'Alice', age: 15 }// , { name: 'Alice', age: 16 }// ]并且毫不费力地reverse进行任何分类。在这里我们排序name然后反向排序age-data.sort(concat(sortByName, reverse(sortByAge)))// [ { name: 'Alice', age: 16 }// , { name: 'Alice', age: 15 }// , { name: 'Alice', age: 10 }// , { name: 'Alicia', age: 10 }// ]功能原理我们的Comparison模块灵活而可靠。这使我们能够以类似公式的方式编写排序器 -// this...concat(reverse(sortByName), reverse(sortByAge))// is the same as...reverse(concat(sortByName, sortByAge))与concat表达式类似 -// this...concat(sortByYear, concat(sortByMonth, sortByDay))// is the same as...concat(concat(sortByYear, sortByMonth), sortByDay)// is the same as...nsort(sortByYear, sortByMonth, sortByDay)发疯nsort现在假设我们要按任意数量的因素进行排序。例如,对日期对象进行排序需要三个比较:year、month和day-const { empty, map, reverse, nsort } = Comparisonconst data = [ { year: 2020, month: 4, day: 5 } , { year: 2018, month: 1, day: 20 } , { year: 2019, month: 3, day: 14 } ]const sortByDate = nsort ( map(empty, x => x.year) // primary: sort by year , map(empty, x => x.month) // secondary: sort by month , map(empty, x => x.day) // tertiary: sort by day )现在我们可以按year, month, day-排序data.sort(sortByDate)// [ { year: 2019, month: 11, day: 14 }// , { year: 2020, month: 4, day: 3 }// , { year: 2020, month: 4, day: 5 }// ]并且同样可以轻松地按year, month, day-进行反向排序data.sort(reverse(sortByDate))// [ { year: 2020, month: 4, day: 5 }// , { year: 2020, month: 4, day: 3 }// , { year: 2019, month: 11, day: 14 }// ]由于功能原理,实现 N 排序变得轻而易举。我们concat并empty尽一切努力——const Comparison = { // ... , nsort: (...m) => m.reduce(Comparison.concat, Comparison.empty) }展开下面的代码片段以查看此代码的实际效果 -const Comparison = { empty: (a, b) => a < b ? -1 : a > b ? 1 : 0 , map: (m, f) => (a, b) => m(f(a), f(b)) , concat: (m, n) => (a, b) => Ordered.concat(m(a, b), n(a, b)) , reverse: (m) => (a, b) => m(b, a) , nsort: (...m) => m.reduce(Comparison.concat, Comparison.empty) }const Ordered = { empty: 0 , concat: (a, b) => a === 0 ? b : a }const { empty, map, concat, reverse, nsort } = Comparisonconst sortByDate = nsort ( map(empty, x => x.year) // primary , map(empty, x => x.month) // secondary , map(empty, x => x.day) // tertiary )const data = [ { year: 2020, month: 4, day: 5 } , { year: 2019, month: 11, day: 14 } , { year: 2020, month: 4, day: 3 } ]console.log(data.sort(reverse(sortByDate)))// [ { year: 2020, month: 4, day: 5 }// , { year: 2020, month: 4, day: 3 }// , { year: 2019, month: 11, day: 14 }// ]JavaScript 模块上面Comparison和Ordered被定义为简单对象。JavaScript 是一种非常灵活的语言,并且import语法export明确可用于模块化您的程序。以这种方式编写模块可以让我们清楚地了解事情应该去哪里,并为我们提供足够的空间来扩展我们的代码 -// Comparison.jsimport { lt, gt, eq, concat:_concat } from "./Ordered"const asc = (a, b) => (console.log(a, b), a < b) ? lt : a > b ? gt : eqconst empty = ascconst map = (m, f) => (a, b) => m(f(a), f(b))const concat = (m, n) => (a, b) => _concat(m(a, b), n(a, b))const reverse = (m) => (a, b) => m(b, a)const desc = reverse(asc)export { asc, concat, desc, empty, map, reverse }// Ordered.jsconst lt = -1const gt = 1const eq = 0const empty = eqconst concat = (a, b) => a === eq ? b : aexport { concat, empty, eq, gt, lt }