简体   繁体   中英

How do I make sort json object values in discord.js code block?

My current code:

const fetch = require("node-fetch");    
const data = await fetch(
      `https://pokemonrevolution.net/spawns/land_spawns.json`
    ).then((res) => res.json());

    const filterFromPoke = data.filter((p) => p.Pokemon === "Pikachu");

    const filteredMap = filterFromPoke
      .map((s) =>
        `${s.Map}        Land                    Tier ${s.Tier}  ${s.MinLVL}-${s.MaxLVL}    ${s.MemberOnly}     ${s.Item}`
          .replace("null", "-")
          .replace("false", "No")
          .replace("true", "Yes")
      )
      .reduce((spw, spnxt) => {
        spw = spw + "\n";
        return spw + spnxt;
      });

    const mssg = `\`\`\`md\n#Map                               Area    Rarity    Levels    MS    Time    Item\n${filteredMap}\`\`\``;

message.channel.send(mssg);

Returns: Image link

I want it to return something like this click here

Could someone please help me out to sort that clean like the example? Thanks

First, I thought that you could do it with embeds, but as Discord only displays three columns, so this one didn't work as expected. I'm just leaving it here, because if someone has only three columns max, it works fine.

client.on('message', async (message) => {
  if (message.author.bot) return;

  const res = await fetch('https://pokemonrevolution.net/spawns/land_spawns.json');
  const data = await res.json();
  const filteredData = data.filter((p) => p.Pokemon === 'Pikachu');
  const embed = new MessageEmbed().setTitle('Pokemons');

  const obj = { map: '', area: '', tier: '', levels: '', ms: '', item: '' };

  filteredData.forEach((spawn) => {
    obj.map += `\n${spawn.Map}`;
    obj.area += `\nLand`;
    obj.tier += `\n${spawn.Tier}`;
    obj.levels += `\n${spawn.MinLVL}-${spawn.MaxLVL}`;
    obj.ms += `\n${spawn.MemberOnly ? 'Yes' : 'No'}`;
    obj.item += `\n${spawn.Item ? spawn.Item : '-'}`;
  });

  embed.addFields(
    { name: '#Map', value: obj.map, inline: true },
    { name: 'Area', value: obj.area, inline: true },
    { name: 'Tier', value: obj.tier, inline: true },
    { name: 'Levels', value: obj.levels, inline: true },
    { name: 'MS', value: obj.ms, inline: true },
    { name: 'Item', value: obj.item, inline: true },
  );

  message.channel.send(embed);
});

The result looked like this:

在此处输入图像描述

Endothermic_Dragon's solution was a bit closer to what you wanted, so I made an improved version of theirs. You can find it below:

client.on('message', async (message) => {
  if (message.author.bot) return;

  const res = await fetch('https://pokemonrevolution.net/spawns/land_spawns.json');
  const data = await res.json();
  const filteredData = data.filter((p) => p.Pokemon === 'Pikachu');

  // number of empty characters between columns
  const padding = 3;

  const lengths = filteredData.reduce(
    (acc, curr) => {
      const level = `${curr.MinLVL}-${curr.MaxLVL}`;
      const tier = curr.Tier.toString();

      return {
        levels: level.length > acc.levels ? level.length : acc.levels,
        map: curr.Map.length > acc.map ? curr.Map.length : acc.map,
        memberOnly: curr.memberOnly ? 'Yes'.length : 'No'.length,
        tier: tier.length > acc.tier ? tier.length : acc.tier,
      };
    },
    {
      levels: 0,
      map: 0,
      memberOnly: 0,
      tier: 0,
    },
  );
  const header = [
    '#Map'.padEnd(lengths.map + padding),
    'Area'.padEnd('Area'.length + padding),
    'Rarity'.padEnd(lengths.tier + 'Tier '.length + padding),
    'Levels'.padEnd(lengths.levels + padding),
    'Members Only'.padEnd('Members Only'.length + padding),
    'Item',
  ].join('');

  const table = filteredData.map((d) => [
      d.Map.padEnd(lengths.map + padding),
      'Land'.padEnd('Land'.length + padding),
      `Tier ${`${d.Tier}`.padEnd(lengths.tier + padding)}`,
      `${d.MinLVL}-${d.MaxLVL}`.padEnd(lengths.levels + padding),
      `${d.MemberOnly ? 'Yes' : 'No'}`.padEnd('Members Only'.length + padding),
      d.Item ? d.Item : '-',
    ].join(''))
    .join('\n');

  message.channel.send(`\`\`\`md\n${header}\n${table}\`\`\``);
});

It seems to be working as expected:

在此处输入图像描述

If you want to fetch from another endpoint if the first one yield no results, you can use the following code. I've made a few other changes and tried to add comments too:

function getDaytimeNames(daytime = []) {
  let names = ['M', 'D', 'N'];
  return daytime
    .reduce((acc, curr, i) => (curr ? [...acc, names[i]] : acc), [])
    .join('/');
}

async function fetchData(pokemon) {
  let res = await fetch('https://pokemonrevolution.net/spawns/land_spawns.json');
  let data = await res.json();
  let reducer = (area) => (acc, curr) => curr.Pokemon.toLowerCase() !== pokemon.toLowerCase()
    ? acc
    : [
        ...acc,
        {
          area,
          daytime: getDaytimeNames(curr.Daytime),
          item: curr.Item ? curr.Item : '-',
          levels: `${curr.MinLVL}-${curr.MaxLVL}`,
          map: curr.Map,
          memberOnly: `${curr.MemberOnly ? 'Yes' : 'No'}`,
          tier: `Tier ${curr.Tier}`,
        },
      ];
  let landReducer = reducer('Land');
  let filteredData = data.reduce(landReducer, []);

  if (filteredData.length > 0)
    return filteredData;

  let surfReducer = reducer('Surf');
  // If there was no filtered data from land_spawns, try surf_spawns
  res = await fetch('https://pokemonrevolution.net/spawns/surf_spawns.json');
  data = await res.json();
  filteredData = data.reduce(surfReducer, []);

  return filteredData;
}

function createTable(data, padding) {
  const addPadding = (str, length) => str.padEnd((length || str.length) + padding);
  const getMaxLengths = (acc, curr) => {
    const getLongest = (prop) => curr[prop].length > acc[prop] ? curr[prop].length : acc[prop];
    return {
      area: getLongest('area'),
      daytime: getLongest('daytime'),
      levels: getLongest('levels'),
      map: getLongest('map'),
      memberOnly: getLongest('memberOnly'),
      tier: getLongest('tier'),
    };
  };

  const lengths = data.reduce(getMaxLengths, {
    area: 0,
    daytime: 0,
    levels: 0,
    map: 0,
    memberOnly: 0,
    tier: 0,
  });

  const headers = [
    addPadding('#Map', lengths.map),
    addPadding('Area', lengths.area),
    addPadding('Daytime'),
    addPadding('Rarity', lengths.tier),
    addPadding('Levels', lengths.levels),
    addPadding('Members Only'),
    // No padding needed as it's the last column
    'Item',
  ].join('');

  const createRow = (d) => [
    addPadding(d.map, lengths.map),
    addPadding(d.area, lengths.area),
    addPadding(d.daytime, 'Daytime'.length),
    addPadding(d.tier, lengths.tier),
    addPadding(d.levels, lengths.levels),
    addPadding(d.memberOnly, 'Members Only'.length),
    d.item,
  ].join('');

  const table = data.map(createRow).join('\n');

  return `${headers}\n${table}`;
}

// Create an array of rows with a max length
// making sure it always has complete rows only
function chunkify(str, max) {
  let chunks = [];

  while (str.length > max) {
    let i = str.substr(0, max).lastIndexOf('\n');
    chunks.push(str.substr(0, i));
    str = str.substr(i + 1, str.length);
  }
  if (str.length > 0) {
    chunks.push(str);
  }
  return chunks;
}

client.on('message', async (message) => {
  if (message.author.bot) return;

  const args = message.content.slice(prefix.length).split(/ +/);
  const command = args.shift().toLowerCase();
  const pokemon = args[0];

  const data = await fetchData(pokemon);

  // Number of empty characters between columns
  const padding = 2;
  // Discord only allows a maximum of 2000 characters for content
  const maxLength = 1980;
  const table = createTable(data, padding);

  chunkify(table, maxLength)
    .forEach((chunk) => message.channel.send(`\`\`\`md\n${chunk}\`\`\``));
});

在此处输入图像描述

Try this:

 fetch(`https://pokemonrevolution.net/spawns/land_spawns.json`).then((res) => res.json()).then(data => data.filter((p) => p.Pokemon === "Pikachu")).then(data => { var mapLength = 0, tierLength = 0, minLevelLength = 0, maxLevelLength = 0, memberOnlyLength = 0, itemLength = 0; data.forEach(dataPoint => { mapLength = (mapLength > dataPoint.Map.length)? mapLength: dataPoint.Map.length; tierLength = (tierLength > dataPoint.Tier.toString().length)? tierLength: dataPoint.Tier.toString().length; minLevelLength = (minLevelLength > dataPoint.MinLVL.toString().length)? minLevelLength: dataPoint.MinLVL.toString().length; maxLevelLength = (maxLevelLength > dataPoint.MaxLVL.toString().length)? maxLevelLength: dataPoint.MaxLVL.toString().length; if (dataPoint.MemberOnly) { memberOnlyLength = (memberOnlyLength > "Yes")? memberOnlyLength: 3 } else { memberOnlyLength = (memberOnlyLength > "No")? memberOnlyLength: 2 } }) console.log(mapLength) console.log(tierLength) console.log(minLevelLength) console.log(maxLevelLength) console.log(memberOnlyLength) console.log(itemLength) data.map(dataPoint => { dataPoint.Map = dataPoint.Map.padEnd(mapLength + 5) dataPoint.Tier = dataPoint.Tier.toString().padEnd(tierLength + 5) dataPoint.MinLVL = dataPoint.MinLVL.toString().padEnd(minLevelLength + 5) dataPoint.MaxLVL = dataPoint.MaxLVL.toString().padEnd(maxLevelLength + 5) if (dataPoint.MemberOnly) { dataPoint.MemberOnly = "Yes".padEnd(memberOnlyLength + 5) } else { dataPoint.MemberOnly = "No".padEnd(memberOnlyLength + 5) } if (dataPoint.Item == null) { dataPoint.Item = "-" } return dataPoint }) totalString = "#Map".padEnd(mapLength + 5) + "Area " + "Rarity".padEnd(tierLength + 5) + "Min LVL".padEnd(minLevelLength + 5) + "Max LVL".padEnd(maxLevelLength + 5) + "Members Only".padEnd(memberOnlyLength + 5) + "Item" + "\n"; data.forEach(dataPoint => { totalString += [dataPoint.Map, "Land ", "Tier " + dataPoint.Tier, dataPoint.MinLVL, dataPoint.MaxLVL, dataPoint.MemberOnly, dataPoint.Item].join('') + "\n" }) console.log(totalString) })

Note that the JS won't work here because of CORS, but it should work when you actually do it. Here's a screenshot of it working:

在此处输入图像描述

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM