排序器
排序器可以高性能的完成排序和分页读取任务。
一个领域可以有很多个排序器,每个排序器之间通过排序器名称来区分。
一个排序器中会存有很多
名称-排序值
的记录。其中名称是这个记录的标签,可以是玩家ID、公会名、帖子ID等任意文本和整数。排序值是这个记录被排序的依据,可以是时间戳、物品数量等要被排序的数字和文本。─ 排序器名称 (排序器会从小到大自动对记录进行排序)
│ ├─ 名字1, 排序值1 (记录的名称为“名字1”,排序值1 是所有记录中最小的值)
│ ├─ 名字2, 排序值2 (排序值2 是所有记录中第二小的值,以此类推)
│ ├─ 名字3, 排序值3
│ ├─ 名字4, 排序值4
一个典型的排序器可以是下面这个样子:
├─ 金钱
│ ├─ 64b28529a204de1c560725c8, 201 (记录的名字是玩家ID,排序值是该玩家的金钱数)
│ ├─ 64b28529a204de1c560725c9, 380.5
│ ├─ 64b28529a204de1c560725cc, 395
│ ├─ 64b28529a204de1c560725ca, 408
排序器常见使用代码如下:
var 金钱排序器 = 排序器('金钱'); // 加载一个名字叫做“金钱”的排序器
金钱排序器.写(玩家.id, 玩家.属性.金钱); // 向该排序器写入玩家id和该玩家具有的金钱
var 榜一玩家id = 金钱排序器.查(-1); // 返回金钱最多的玩家的id
加载排序器
通过
排序器(排序器名称)
加载一个排序器。var 金钱排序器 = 排序器('金钱');
写入记录
通过
xxx.写(记录名, 排序值)
向排序器写入一个记录。排序器会根据排序值的大小对记录进行排序。向排序器写入记录后,排序器会一直保存这个记录(即使这个脚本已经结束),直到记录被删除或排序器被清空。
var 金钱排序器 = 排序器('金钱');
金钱排序器.写(玩家.id, 玩家.属性.金钱);
属性.临时文本 = '排行榜数据已更新,你已加入排行榜';
查询特定位置的记录名
通过
xxx.查(位置)
从排序器中根据排序结果查找一个记录名。位置为 0 表示查最小值,1表示第二小的值,-1 则表示查最大值。var 金钱排序器 = 排序器('金钱');
var 榜一玩家id = 金钱排序器.查(-1); // 返回金钱最多的玩家的id
var 榜二玩家id = 金钱排序器.查(-2); // 返回金钱第二多的玩家的id
var 新人玩家id = 金钱排序器.查(0); // 返回金钱最少的玩家的id
var 摸鱼玩家id = 金钱排序器.查(1); // 返回金钱第二少的玩家的id
批量查询
通过
xxx.批量查(位置, 数量)
从排序器中批量查询记录,返回的结果是记录名数组。当位置≥0时,从小到大查。当位置<0时,从大到小查。var 金钱排序器 = 排序器('金钱');
var 财富排行 = 金钱排序器.批量查(-1, 10); // 返回金钱最多的十个玩家id数组,数组首位是金钱最多的
var 摸鱼排行 = 金钱排序器.批量查(0, 10); // 返回金钱最少的十个玩家id数组,数组首位是金钱最少的
删除
通过
xxx.删除(记录名)
从排序器中删除一个记录。var 金钱排序器 = 排序器('金钱');
金钱排序器.删除(玩家.id); // 从排行中去除该玩家
属性.临时文本 = '你成功退出了排行榜';
清空
通过
xxx.清空()
清空该排序器。var 金钱排序器 = 排序器('金钱');
金钱排序器.清空();
属性.临时文本 = '排行榜已清空';
常见用例
通过排序器的特性,你可以高效的实现排序和分页查询的功能。
排行榜
你可以用排序器实现排行榜。
var 金钱排序器 = 排序器('金钱');
var 玩家id数组 = 金钱排序器.批量查(-1, 20) // 取金钱前20的玩家
var 临时文本 = '金钱排行榜';
for(var 序号 = 0; 序号 < 玩家id数组.length; 序号++){
var 当前玩家 = 查找玩家(玩家id);
var 排名 = 序号 + 1;
临时文本 += '\n' + 排名 + '. ' + 当前玩家.名字 + ' 金钱:' + 当前玩家.属性.金钱;
}
可以获得特定玩家所在的排名。
var 金钱排序器 = 排序器('金钱');
var 玩家id数组 = 金钱排序器.批量查(-1, 100) // 在金钱前 100 的玩家中查找
var 排名 = 玩家id数组.indexOf(玩家.id) + 1
if (排名 > 0) {
属性.临时文本 = '你的金钱排名为:' + 排名 + '。';
}else{
属性.临时文本 = 'Ooops,没有在金钱榜前 100 名中找到你…';
}
分页查询
在排序器中查询数据很快,相当于直接从数据库中读取数据。
对于列表类应用来说,如果使用
数据.目录
查询全部记录,随着记录数量的增加,返回的数组会越来越大。这会影响脚本性能,甚至让脚本超时,无法使用。这时,使用排序器
进行批量查询,性能就会好得多。因为排序器是在写入数据时进行排序的,当从已经排序好的数据中查询时,不会有额外的性能损失。在列表类应用使用排序器的思路是,当用户添加记录时,脚本向数据库写入数据,同时也向排序器写入该记录的id(例如时间戳或自增序号)。在查询时,使用
批量查
,根据当前页数读取特定的记录。var 每页数量 = 10
// 当页数为 1 时,位置为 -1,表示查找时间最大的记录
// 当页数为 2 时,位置为 -11,表示查找相隔 10 个记录后的记录,从而实现翻页效果
var 位置 = -(属性.页数 - 1) * 每页数量 - 1
var 市场记录排序器 = 排序器('市场记录')
var 市场id数组 = 市场记录排序器.批量查(位置, 每页数量)
var 价格 = 数据.读(['市场', 市场id数组[0], '价格'])
// ...
你可以在这个领域中查看完整的例子,这个领域实现了一个待办事项,支持用户添加、删除和修改事项。重点是用户添加和删除事项的逻辑(在相应的按钮里)。
待办事项
Realm·这是一个功能领域,你可以在这个领域记录要做的事情。
该领域通过组件系统创建了可以记录待办事项的应用。领域综合考虑了性能、可维护性和样式设计的因素,是使用组件和数据库的范例,非常适合学习。
领主可以参考该领域编写需要换页的列表应用,以确保性能和可维护性。
Realm 官方的开源领域,是 Realm 教学和开发体系的一部分,其代码和想法可以被任意复制、修改和使用,相当于原创,不需要标注和署名。
https://realm.host/to/_64a6c67d163be8d53bc5da84
注意事项
排序器不是一次性的,不应该每次都向排序器写入所有数据,这会导致排序器每次都重新排序了一遍。而是应当在数据发生变化时,实时写入排序器。
例如,如果想做一个金钱排行榜,不应该在玩家查询排行榜时,批量读取全部玩家的金钱,写入排序器。正确的方法是,封装一个“设置金钱”的函数,在这个函数中,会改变“金钱”属性的值,同时将新的值写入排序器中。这样,改变玩家的金钱时,可以顺便将该玩家的金钱数写入排序器。玩家每次查看排行榜时,就可以查询已经排序好的数据。