排序器

排序器可以高性能的完成排序和分页读取任务。
一个领域可以有很多个排序器,每个排序器之间通过排序器名称来区分。
一个排序器中会存有很多名称-排序值的记录。其中名称是这个记录的标签,可以是玩家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], '价格'])
// ...

注意事项

排序器不是一次性的,不应该每次都向排序器写入所有数据,这会导致排序器每次都重新排序了一遍。而是应当在数据发生变化时,实时写入排序器。
例如,如果想做一个金钱排行榜,不应该在玩家查询排行榜时,批量读取全部玩家的金钱,写入排序器。正确的方法是,封装一个“设置金钱”的函数,在这个函数中,会改变“金钱”属性的值,同时将新的值写入排序器中。这样,改变玩家的金钱时,可以顺便将该玩家的金钱数写入排序器。玩家每次查看排行榜时,就可以查询已经排序好的数据。