资讯专栏INFORMATION COLUMN

用sort实现orderby

jiekechoo / 2724人阅读

摘要:工作到了这个年数感觉那些基本函数语法已经跟人合一了根本不会为操作一些数据结构而思考半天了在做小程序的时候遇到了个的场景结果发现没有以为的那么简单也许是之前不求甚解的原因那么现在来解决的问题问题的产生与探讨方向在小程序中有个将的某一条置顶的需

工作到了这个年数, 感觉那些基本函数语法已经跟人合一了, 根本不会为操作一些数据结构而思考半天了. 在做小程序的时候遇到了个orderby的场景, 结果发现没有以为的那么简单. 也许是之前不求甚解的原因, 那么现在来解决orderby的问题.

问题的产生与探讨方向

在小程序中有个将list的某一条置顶的需求, 在初始化数据到时候可以使用数据库的orderby, 但在更新数据以后再重新初始化就显得有些不妥, 所以我尝试直接使用computed列表来解决这个问题.

所以现在的问题是: 输入list, 输出orderby置顶字段.

之前以为的sort很简单, 我就尝试了: arr.sort(i => i.stick). 字面看起来是根据stick字段来排序. 输出结果一团糟. 仔细思考了下又尝试了别的方法, 还是失败, 才决定仔细想一下应该如何处理.

对sort的理解与快速shuffle

先说一下之前对sort的理解.

sort接受的参数返回大于0或者小于0. 根据结果来排序.

所以有一个快速shuffle数组的方法:

arr.sort(() => Math.random() - 0.5)

因为函数的返回结果一半是大于0一半是小于0的(不严格, 但之后也认为概率是一半一半). 所以任何输出进行了如此处理, 都会变成一个随机顺序的数组.

另外一个例子, 对一个数组: [1, 2, 3, 4, 5, 10, 11, 12]进行排序, 如果不传参数排序结果是错的, 因为默认是localCompare. 所以要写成:

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

这样才能得到正确从小到大的排列.

以上就是我多年以来对sort的所有理解. 所以才会写出上面的: arr.sort(i => i.stick)这样搞笑的东西. 因为理解是有问题的.

sort是如何排序的

因为不知道sort函数得到了结果后是如何排序的. 所以对sort的理解有问题. 而我们知道reduce就是从头到尾遍历并传递每次计算的结果. sort却不知道. 所以打出每次的返回值来看一下每次得到返回值后sort做了些什么.

我们要对不同数组进行同样的操作, 排序方法是一样的, 先写一下:

const log = (a, b) => {
    console.log(a, b, a - b > 0)
    return a - b
}

开始对不同数组进行排序: 先来1到5

[1, 2, 3, 4, 5].sort(log)

结果: [1, 2, 3, 4, 5]

2 1 true
3 2 true
4 3 true
5 4 true

尝试: 从5到1

[5, 4, 3, 2, 1].sort(log)

结果: [1, 2, 3, 4, 5]

4 5 false
3 4 false
2 3 false
1 2 false

目前看来, sort应该是插入排序.

[3, 5, 7, 9, 2, 1, 6].sort(log)

看log的时候我把当前排序结果也打一下:

5 3 true [3, 5]
7 5 true [3, 5, 7]
9 7 true [3, 5, 7, 9]
2 9 false // 2还是与当前最大的9比.结果第一次false
2 7 false // 于是一路比下来
2 5 false
2 3 false // 比到最小的, 于是确定了位置 [2, 3, 5, 7, 9]
1 5 false // 1选择了与5比, 此时5是中间位置的数, 而不是最大的数
1 3 false // 然后一个一个比较下来
1 2 false [1, 2, 3, 5, 7, 9]
6 5 true // 6还是于5比, 此时5也是中间位置的数
6 9 false // 没有选择与7, 而是与9比了
6 7 false

从这些log能得出一些粗浅的结论:

sort是插入排序

每次比较的数字会根据两个因素来决定: 分别是之前比较的结果和当前排序的位置

如何实现orderby

首先明确思路:

sort认为每个元素之间的关系是比大小, 所以我们需要做的是写出任意两个元素的相对顺序的普遍公式.

先构建一组数据:

let gnrt = () => ({ age: Math.round(Math.random() * 50), height: Math.round(Math.random() * 200) })
let arr = Array.from({length: 10}).map(() => gnrt())

我们先建立纯数字, 无顺序的orderby来理这个思路.

let orderby = function (arr, ...orders) {
    return arr.sort((a, b) => {
        let res = 0
        for (let order of orders) {
            if (a[order] - b[order] !== 0) {
                res = a[order] - b[order]
                break
            } 
        }
        return res
    })
}

调用orderby(arr, "height", "age")就得到了理想的orderby结果了: 根据权重排序, 如果都一样就保持顺序.

#后续#

这个思路清晰以后, 做兼容就容易了:

如果要指定顺序, 在排序参数里带特征, 例如"height", "-height", 来决定在执行的时候是a - b 还是b - a.

如果要指定排序函数(在非数字情况下). 把排序参数改写成兼容function的, 判断是string就执行默认, 是function就调用function即可.

当然, 功能越完善的函数就越复杂, 函数本身只是函数复杂度和业务复杂度交换的作用. 具体实现就不写了.

所以置顶排序如何实现

我们已经想清楚了orderby的实现, 那么置顶排序是stick这个布尔值字段, 就必须根据我上面说的传函数进去, 并且改写orderby函数.

这样又要多些2个函数, 所以我选择:

[...arr.filter({stick} => stick), ...arr.filter({stick} => !stick)]

搞定.

原文地址

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/100311.html

相关文章

  • Laravel 多条件 where 查询语句

    摘要:在使用开发应用的时候,还是会经常遇到多条件的查询语句,比如一个网站的商品筛选页面就有可能是这样子这种方式的筛选其实我们就会使用多条件的语句来做,比如我们通常会看到类似下面的代码那如果说,你需要一个默认的排序结果的话, 在使用 Laravel 开发应用的时候,还是会经常遇到多条件的查询语句,比如一个网站的商品筛选页面就有可能是这样子: http://jd.com/products?col...

    sanyang 评论0 收藏0
  • React-Redux小应(一)-React_Redux_Appointment

    摘要:先来一波硬广我的博客欢迎观光传送门这个小应用使用创建演示地址,地址。这是之前的的版,之前的演示,改写自的课程。 React-Redux-Appointment 先来一波硬广:我的博客欢迎观光:传送门这个小应用使用Create React App创建,演示地址:https://liliang-cn.github.io/react_redux_appointment,repo地址:http...

    CoorChice 评论0 收藏0
  • 前端数据模型Model;适于多人团队协作的开发模式

    摘要:前言本文讲述的数据模型并不是一个库,也不是需要的包,仅仅只是一种在多人团队协作开发的时候拟定的规则。至少目前为止,我们的开发团队再也没用过虽然一开始也没用,也不用担心后台数据的字段或结构发生变动,真正实现前后台并行开发的愉快模式。 前言 本文讲述的数据模型并不是一个库,也不是需要npm的包,仅仅只是一种在多人团队协作开发的时候拟定的规则。至少目前为止,我们的开发团队再也没用过mock(...

    linkFly 评论0 收藏0
  • 30-seconds-code——Object

    摘要:英文文章来源于删除对象中除指定键值的属性用递归的方法用方法遍历对象然后删除不是在给定数组中的属性如果你传入,它将对该键所对应的对象进行深度遍历的变形非原著作对所有的键对应的对象进行深度遍历用方法遍历对象然后删除不是在给定数组中的属性如 英文文章来源于:https://github.com/Chalarangelo/30-seconds-of-code/blob/master/READM...

    lbool 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<