写了一个 [排序只需要修改一个对象数据] 的模式 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
请不要在回答技术问题时复制粘贴 AI 生成的内容
rizon
V2EX    程序员

写了一个 [排序只需要修改一个对象数据] 的模式

  • nbsp;
  •   rizon
    othorizon 2023 年 12 月 10 日 1655 次点击
    这是一个创建于 773 天前的主题,其中的信息可能已经有所发展或是发生改变。

    废话:
    最近在对 notelive.cc 这个网站做一个新版本(不会替代这个网站,只是做一个新项目),然后遇到了目录树的排序老问题。

    正题:
    出于降低数据库写压力,简化初始化数据结构,以及我就是不喜欢排序要修改两个对象的个人原因等,因此做了这个排序模型。 实现效果:

    1. 数据结构初始化不需要包含排序信息(个人业务需要,默认按照时间排序,本 demo 里按照 id 排序)
    2. 排序时只需要修改拖动的对象的数据,不需要操作目标位置的对象。

    有什么好的优化建议,也欢迎贴出来。

    Edit single-sort

    "use client"; import { useRef, useState } from "react"; interface Item { id: number; orderTime: number | undefined; pre: number | null | undefined; } let init: Item[] = [ { id: 1, orderTime: undefined, pre: undefined, }, { id: 4, orderTime: undefined, pre: undefined, }, { id: 2, orderTime: undefined, pre: 3, }, { id: 3, orderTime: undefined, pre: undefined, }, ]; export default function SortPage() { const source = useRef<HTMLInputElement>(null); const target = useRef<HTMLInputElement>(null); const [list, setList] = useState<Item[]>(init); const doSort = () => { if (!source.current || !source.current.value) { setList(reSort(list)); return; } const sourceItem = list.find( (item) => item.id == parseInt(source.current!.value) ); if (!sourceItem) { alert("not fount sourceItem"); return; } const targetItem = target.current!.value ? list.find((item) => item.id == parseInt(target.current!.value)) : null; // 只需要修改 sourceItem 的值,不用处理 targetItem if (!targetItem) { sourceItem.orderTime = Date.now(); sourceItem.pre = -1; } else { sourceItem.orderTime = Date.now(); sourceItem.pre = targetItem.id; } setList(reSort(list)); }; return ( <div> <div> <div> 移动的元素: <input className="border" ref={source} type="text" /> </div> <div> 目标元素的后面(留空首位):{" "} <input className="border" ref={target} type="text" /> </div> <div> <button className="bg-gray-400 p-2" OnClick={doSort}> 移动 </button> </div> </div> <div className="mt-5 flex items-center justify-start gap-x-2 px-3"> {list.map((item) => { return ( <div className="bg-blue-100 p-2 " key={item.id}> <p>id: {item.id}</p> <p>orderTime: {item.orderTime}</p> <p>pre: {item.pre}</p> </div> ); })} </div> </div> ); } function reSort(originList: Item[]) { const list = [...originList]; const sortById = (pre: Item, next: Item) => { // id 从小到大排序 if (pre.id > next.id) { return 1; } else if (pre.id < next.id) { return -1; } return 0; }; const sortByOrderTime = (pre: Item, next: Item) => { let preOrderTime = pre.orderTime || 0; let nextOrderTime = next.orderTime || 0; // orderTime 从小到大排序 if (preOrderTime > nextOrderTime) { return 1; } else if (preOrderTime < nextOrderTime) { return -1; } return 0; }; list.sort(sortById).sort(sortByOrderTime); const checkList = [...list]; // 按照 orderTime 从旧到新,每个元素都执行一次 pre 位置调整处理,如果两个元素的 pre 相同,orderTime 最晚的则会插入到旧数据的前面 for (let i = 0; i < checkList.length; i++) { const checkItem = checkList[i]; if (checkItem.pre) { moveElementAfter(list, checkItem.id, checkItem.pre); } } function moveElementAfter( array: Item[], sourceId: number, targetItemId: number ) { const sourceIdx = array.findIndex((e) => e.id === sourceId); if (sourceIdx === -1) { return; } const sourceItem = array[sourceIdx]; const indexToInsert = list.findIndex((e) => e.id === targetItemId); array.splice(sourceIdx, 1); if (indexToInsert > -1) { array.splice(indexToInsert + 1, 0, sourceItem); // 在目标元素后面插入 } else { array.unshift(sourceItem); // 如果找不到元素 b ,则将元素 a 放在数组首位 } } return list; } 

    文末: 如果大家对 notelive.cc 这个网站有什么建议,或对正在内测的新笔记产品有兴趣,或单纯想要唠唠嗑,可以加微信群哈。

    notelive

    第 1 条附言    2023 年 12 月 10 日
    行不通。已放弃,最后做的的方案就是每改变一个元素就全 order 排序了。考虑到每个子文件夹下的数量还好,就这么简单的搞了。
    其实还有考虑单独存储排序数据,后来想想算了。
    7 条回复    2023-12-10 19:30:07 +08:00
    rizon
        1
    rizon  
    OP
       2023 年 12 月 10 日
    擦 有问题,有些场景不对。忽略吧
    renmu
        2
    renmu  
       2023 年 12 月 10 日 via Android
    只要取到目标前后对象的 sort 值,然后将这这两个值和的一半写入目标就可以了
    zhy0216
        3
    zhy0216  
       2023 年 12 月 10 日 via Android
    @renmu 最后会有精度问题的
    renmu
        4
    renmu  
       2023 年 12 月 10 日 via Android
    @zhy0216 你先算一下多少次能达到精度问题,这是一个很小概率的事情,就算有,完全可以做个额外处理
    zhy0216
        5
    zhy0216  
       2023 年 12 月 10 日 via Android
    @renmu 只要有存在的可能就要额外处理 感觉不够好而已
    rizon
        6
    rizon  
    OP
       2023 年 12 月 10 日
    @renmu #2
    @zhy0216 #3 以前也想过这个办法,两个元素之间留数字的空间,这样每次排序只改变一个的值。
    但是时间久了还要执行一次刷库操作,不然总有用完的时候,或者就想说的精度问题
    rizon
        7
    rizon  
    OP
       2023 年 12 月 10 日
    @rizon #6 而且这个方案,要求第一次写入的数据就要有顺序。
    我其实核心想实现的事,如果未做排序,就不产生大量的排序数据,按创建时间降序排序即可。
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     3662 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSON: 3.9.8.5 27ms UTC 04:27 PVG 12:27 LAX 20:27 JFK 23:27
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86