如何按某个属性排序进行映射

Posted

技术标签:

【中文标题】如何按某个属性排序进行映射【英文标题】:How to map by sorting by a certain property 【发布时间】:2019-11-23 05:10:44 【问题描述】:

我想在我的机器人... - 从类别和 VC 频道中排除 # - 按数字位置而非字母顺序对频道进行排序

问题是我不知道如何根据类型从频道中拆分 #。我也想不出一种按位置编号对频道进行排序的方法。

我试过这个 .addField("Server's channels", serv.channels.calculatedPosition.map(c =>$c).join(' | '),true)

.addField("Server's channels", serv.channels.map(c =>$c).position.join(' | '),true)

var serv = message.guild

    var myInfo = new discord.RichEmbed()
        .setAuthor(`$serv.name's channels`,`$message.guild.iconURL`)
        .addField(`Server's channels`, serv.channels.map(c => `$c`).join(' | '),true)
        .setColor(0xffd000)
        .setFooter('Server Roles.')
        .setThumbnail(`$message.guild.iconURL`)
        message.channel.sendEmbed(myInfo);

期望:discord.js-commando 命令将 # 从不是文本的频道中分离出来,并按位置映射频道。 实际:Bot 按字母顺序映射频道。

【问题讨论】:

【参考方案1】:

排序

GuildChannel.positionGuildChannel.calculatedPosition 的问题在于返回的位置是基于通道的类型。例如,所有类别都被排序并与文本通道分开分配编号,文本通道与语音通道分开。

为了解决这个问题,我们可以制作我们自己的系统来利用它来发挥我们的优势。我们首先对所有类别进行排序并将其添加到与其子项的排序集合配对的集合中。然后,我们遍历并将频道添加到列表中。

格式化

从技术上讲,# 符号应该位于非文本频道的前面,因为 Discord 会将他们的提及转换为使用它。但是,它看起来不是很吸引人,逻辑似乎有点缺陷。

如果不是文本频道,我们所要做的就是使用频道的名称而不是提及它。

守则

您可能需要更改一些变量,并根据需要实现嵌入。这只是一个例子。

const guild = message.guild;

// Comparison function which sorts channels according to appearance within Discord. Name
// is short for 'descending position,' but it also accomodates for voice channel location.
const descPos = (a, b) => 
  if (a.type !== b.type) 
    if (a.type === 'voice') return 1;
    else return -1;
   else return a.position - b.position;
;

// Create a new Collection to hold categories and their children.
const channels = new Discord.Collection();

// Non-category channels without parent categories will appear at the top.
channels.set('__none', guild.channels.filter(channel => !channel.parent && channel.type !== 'category').sort(descPos));

// Add all the categories in order, mapped by their bolded name, into the Collection.
const categories = guild.channels.filter(channel => channel.type === 'category').sort(descPos);
categories.forEach(category => channels.set(category.id, category.children.sort(descPos)));

const list = [];

// Iterate through the categories and the corresponding Collection of their channels.
for (let [categoryID, children] of channels) 
  // Retrieve the category from it's ID.
  const category = guild.channels.get(categoryID);

  // Push the category name (bolded for readability) into the list.
  if (category) list.push(`**$category.name**`);

  // Iterate through the Collection of children. Push the mention for text, name for others.
  for (let [, child] of children) list.push(child.type === 'text' ? child : child.name);
  // To answer your comment about adding the emoji for voice channels...
  //                              list.push(child.type === 'text' ? child : `? $child.name`);


// Send the list of channels, appearing exactly how it does on the side. Make sure the
// joined list isn't too long for a message or embed field first to avoid an error.
message.channel.send(list.join('\n'))
  .catch(console.error);

资源

Discord.js 文档:

Stable Master

【讨论】:

我发现了一个问题,机器人忽略了重复的类别(它忽略了第一个但允许重复),有没有办法在语音通道中添加符号? 我已编辑代码以防止出现重复问题。 “向语音通道添加符号”是什么意思? 抱歉回复含糊不清,但我的意思是在语音频道名称前添加表情符号,就像?channelname 我在其中添加了一条评论,向您展示如何做到这一点。警告,它可能会影响名称中已包含表情符号的频道的可读性。

以上是关于如何按某个属性排序进行映射的主要内容,如果未能解决你的问题,请参考以下文章

在值上映射排序(Struct的属性)

通过元素指针的无序映射作为键对向量进行排序

使用 Nhibernate 按未映射的计算属性进行排序

Spark - 如何使用有状态映射器对已排序的 RDD 进行平面映射?

如何对List集合中的对象进行按某个属性排序

如何按索引而不是名称映射 JSON 属性