Leaderboards discord js - node.js

I'm storing the xp in a json file for practice. How can I display the top 10 users? The first time I
would have wanted to sort but I don't know how it would be more efficient.
let xpAdd = Math.floor(Math.random() * 9) + 8;
if(!xp[message.author.id]) {
xp[message.author.id] = {
xp:0,
level:1
};
}
let curxp = xp[message.author.id].xp;
let curlvl = xp[message.author.id].level;
let nxtLevel = xp[message.author.id].level * 300;
xp[message.author.id].xp = curxp + xpAdd;
fs.writeFile("./xp.json", JSON.stringify(xp), (error) => {
if(error) console.log(error);
});
This is the code I store
And with this I show the level of xp
if(!xp[message.author.id]) {
xp[message.author.id] = {
xp: 0,
level:1
};
}
let curxp = xp[message.author.id].xp;
let curlvl = xp[message.author.id].level;
let nxtLevelXp = curlvl * 300;
let difference = nxtLevelXp - curxp;

I'd suggest you should convert your object to an array so that you can format it and sort it however you prefer.
// sample object
// I'm going to show the top three in this example for the interest of space
const xp = {
"ID #1": {
level: 3,
xp: 300,
},
"ID #2": {
level: 4,
xp: 400,
},
"ID #3": {
level: 2,
xp: 200,
},
"ID #4": {
level: 1,
xp: 100,
},
};
// sort entries in order of exp (descending), then single out the top three
let entries = Object.entries(xp).sort(([, a], [, b]) => b.xp > a.xp ? 1 : -1).slice(0, 3);
// map entries to the prefered format using the data in their objects
// (in your actual command, you should use `client.users.cache.get(id).tag`,
// but since I don't have access to the client object here, I'm just writing `id`
entries = entries.map(([id, { level, xp }], idx) => `${idx + 1} - ${id} (level ${level}; ${xp} xp)`);
// join each user by a line break
console.log(entries.join('\n'));
Working With Objects
Object.entries()
Array.prototype.sort()
Array.prototype.map()
Array.prototype.join()

Related

Is there a way to map a json object for the below example?

excel snippet
I am using Mule 4 and am trying to read an excel file, then convert into JSON using Dataweave and update them in salesforce.
Below is the payload which I am getting while I read the excel. I need to convert this into the requested Output Payload.
The values are dynamic. There might be more objects.
Any ideas appreciated.
Thanks.
Input Payload:
{
"X":[
{
"A":"Key1",
"B":"Key2",
"C":"Key3",
"D":"value1",
"E":"value2"
},
{
"A":"",
"B":"",
"C":"Key4",
"D":"value3",
"E":"value4"
},
{
"A":"Key5",
"B":"Key6",
"C":"Key7",
"D":"Value5",
"E":"Value6"
},
{
"A":"",
"B":"",
"C":"Key8",
"D":"Value7",
"E":"Value8"
}
]
}
Output Payload:
[
{
"Key1":{
"Key2":{
"Key3":"value1",
"Key4":"value3"
}
},
"Key5":{
"Key6":{
"Key7":"Value5",
"Key8":"Value7"
}
}
},
{
"Key1":{
"Key2":{
"Key3":"value2",
"Key4":"value4"
}
},
"Key5":{
"Key6":{
"Key7":"Value6",
"Key8":"Value8"
}
}
}
]
The following seems to work.
This is JavaScript. I don't know what the underlying syntax or scripting language is for DataWeave, but between the C-family syntax and inline comments you can probably treat the JS like pseudo-code and read it well enough to recreate the logic.
// I assume you started with a table structure like this:
//
// A B C D E
// == == == == ==
// K1 K2 K3 v1 v2 <~ X[0]
// __ __ K4 v3 v4 <~ X[1]
// K5 K6 K7 v5 v6 <~ X[2]
// __ __ K8 v7 v8 <~ X[3]
//
// So I'm going to call A,B,C,D,E "column labels"
// and the elements in `X` "rows".
// Here's the original input you provided:
input = {
"X": [
{
"A":"Key1",
"B":"Key2",
"C":"Key3",
"D":"value1",
"E":"value2"
},
{
"A":"",
"B":"",
"C":"Key4",
"D":"value3",
"E":"value4"
},
{
"A":"Key5",
"B":"Key6",
"C":"Key7",
"D":"Value5",
"E":"Value6"
},
{
"A":"",
"B":"",
"C":"Key8",
"D":"Value7",
"E":"Value8"
}
]
}
// First let's simplify the structure by filling in the missing keys at
// `X[1].A`, `X[1].B` etc. We could keep track of the last non-blank
// value while doing the processing below instead, but doing it now
// reduces the complexity of the final loop.
input.X.forEach((row, row_index) => {
(Object.keys(row)).forEach((col_label) => {
if (row[col_label].length == 0) {
row[col_label] = input.X[row_index - 1][col_label]
}
});
});
// Now X[1].A is "Key1", X[1].B is "Key2", etc.
// I'm not quite sure if there's a hard-and-fast rule that determines
// which values become keys and which become values, so I'm just going
// to explicitly describe the structure. If there's a pattern to follow
// you could compute this dynamically.
const key_column_labels = ["A","B","C"]
const val_column_labels = ["D","E"]
// this will be the root object we're building
var output_list = []
// since the value columns become output rows we need to invert the loop a bit,
// so the outermost thing we iterate over is the list of value column labels.
// our general strategy is to walk down the "tree" of key-columns and
// append the current value-column. we do that for each input row, and then
// repeat that whole cycle for each value column.
val_column_labels.forEach((vl) => {
// the current output row we're populating
var out_row = {}
output_list.push(out_row)
// for each input row
input.X.forEach((in_row) => {
// start at the root level of the output row
var cur_node = out_row
// for each of our key column labels
key_column_labels.forEach((kl, ki) => {
if (ki == (key_column_labels.length - 1)) {
// this is the last key column (C), the one that holds the values
// so set the current vl as one of the keys
cur_node[in_row[kl]] = in_row[vl]
} else if (cur_node[in_row[kl]] == null) {
// else if there's no map stored in the current node for this
// key value, let's create one
cur_node[in_row[kl]] = {}
// and "step down" into it for the next iteration of the loop
cur_node = cur_node[in_row[kl]]
} else {
// else if there's no map stored in the current node for this
// key value, so let's step down into the existing map
cur_node = cur_node[in_row[kl]]
}
});
});
});
console.log( JSON.stringify(output_list,null,2) )
// When I run this I get the data structure you're looking for:
//
// ```
// $ node json-transform.js
// [
// {
// "Key1": {
// "Key2": {
// "Key3": "value1",
// "Key4": "value3"
// }
// },
// "Key5": {
// "Key6": {
// "Key7": "Value5",
// "Key8": "Value7"
// }
// }
// },
// {
// "Key1": {
// "Key2": {
// "Key3": "value2",
// "Key4": "value4"
// }
// },
// "Key5": {
// "Key6": {
// "Key7": "Value6",
// "Key8": "Value8"
// }
// }
// }
// ]
// ```
Here's a JSFiddle that demonstrates this: https://jsfiddle.net/wcvmu0g9/
I'm not sure this captures the general form you're going for (because I'm not sure I fully understand that), but I think you should be able to abstract this basic principle.
It was a challenging one. I was able to at least get the output you expect with this Dataweave code. I'll put some comments on the code.
%dw 2.0
output application/json
fun getNonEmpty(key, previousKey) =
if(isEmpty(key)) previousKey else key
fun completeKey(item, previousItem) =
{
A: getNonEmpty(item.A,previousItem.A),
B: getNonEmpty(item.B,previousItem.B)
} ++ (item - "A" - "B")
// Here I'm filling up the A and B columns to have the complete path using the previous items ones if they come empty
var completedStructure =
payload.X reduce ((item, acc = []) ->
acc + completeKey(item, acc[-1])
)
// This takes a list, groups it by a field and let you pass also what to
// want to do with the grouped values.
fun groupByKey(structure, field, next) =
structure groupBy ((item, i) -> item[field]) mapObject ((v, k, i1) ->
{
(k): next(k,v)
}
)
// This one was just to not repete the code for each value field
fun valuesForfield(structure, field) =
groupByKey(structure, "A", (key,value) ->
groupByKey(value, "B", (k,v) ->
groupByKey(value, "C", (k,v) -> v[0][field]))
)
var valueColumns = ["D","E"]
---
valueColumns map (value, index) -> valuesForfield(completedStructure,value)
EDIT: valueColumns is now Dynamic

Node.js; list strings from JSON file in order

I have file users.json, which contain, among others, data like this:
[
{
"nick": "user123",
"active24": 579
...
}, {
"nick": "nick",
"active24": 259
...
}
]
I want to make leaderboard, showing top 10 users nicks (from uknown max value of users), based on ther "active24" (from biggest to smallest). I can do it using array, but problem is that bot can't send it using vk-io (reason is not important, so i don't describe it much here, but please, do not save final input as array, but as variables or etc). I want output like:
Var_top1 = `${nick}: ${active24}`;
Var_top2 = `${nick}: ${active24}`;
Var_top3 = `${nick}: ${active24}`;
...
Var_top10 = `${nick}: ${active24}`;
P.S sorry for my bad English
do you want something like this?
const data = [
{
nick: "user111",
active24: 579
},
{
nick: "nick222",
active24: 0
},
{
nick: "nick333",
active24: 84
},
{
nick: "nick444",
active24: 9459
}
];
const sorted = data.sort((a, b) => b.active24 - a.active24);
console.log(JSON.stringify(sorted));
//[{"nick":"nick444","active24":9459},{"nick":"user111","active24":579},{"nick":"nick333","active24":84},{"nick":"nick222","active24":0}]
const top1 = sorted[0];
const top2 = sorted[1];
const top3 = sorted[2];
const top4 = sorted[3];
Order the array using a methodology such as
array.prototype.sort.
Once the array has all members sorted, you just need to print them array[0].nick + ":" + array[0].active24
let jsonObject = [
{
"nick": "user123",
"active24": 579
},
{
"nick": "user234",
"active24": 1
},
{
"nick": "nick",
"active24": 259
}
];
// Orders the array
jsonObject.sort((firstElem, secondElem) => {
if (firstElem.active24 > secondElem.active24) return 1;
if (firstElem.active24 < secondElem.active24) return -1;
return 0;
})
// Prints the entire ordered array
console.log(JSON.stringify(jsonObject, null, 2));
// Prints the nick and the active24 value
for (let i = 0; i < jsonObject.length; i++) {
console.log(jsonObject[i].nick + ":" + jsonObject[i].active24);
}

How do i get a randomly selected string name and still select an existing substring without the code coming out as text

I'm currently trying to get info off of an object but that's randomly selected. I believe that the true problem is that what I wrote is not being taken as a variable for selecting an existing object if not as the variable for the object, I don't know if this is a clear message or not.
Example of what I have tried:
let PK = ["Random1", "Random2", "Random3"]
let PKS = Math.floor(Math.random() * PK.length)
let Random1 = {
name: "Random1",
number: "010"
}
let Random2 = {
name: "Random2",
number: "011"
}
if(message.content.toLowerCase() == "random"){
message.channel.send(PK[PKS].number)
}
There is another thing I have tried which is by using ${}. These are the results:
"Random1.number" or "Random2.number" when what I was looking for is actually "010" or "011".
You should wrap your objects inside some collection such as an Array and then you just compare the value from your random selection to the value find in the collection (if any (randoms)):
let PK = ["Random1", "Random2", "Random3"];
let PKS = Math.floor(Math.random() * PK.length);
const randoms = [
{
name: "Random1",
number: "010",
},
{
name: "Random2",
number: "011",
},
];
if (message.content.toLowerCase() == "random") {
const findRandom = randoms.find((v) => v.name === PK[PKS]);
if (findRandom) {
message.channel.send(findRandom.number);
}
}

I want to select a random XPath from the defined Array

editMethod(){
var num = Math.floor((Math.random() *4) + 1);
var xPath_arr= [
'//android.widget.RadioButton[#text="seat1"]',
'//android.widget.RadioButton[#text="seat2"]',
'//android.widget.RadioButton[#text="seat3"]',
'//android.widget.RadioButton[#text="Notselected"]',
]
xPath_arr[num]
}
Then calling in another function like this
selectseat(){
this.editmethod();
this.doneBtn.click();
}
tried different method but received different errors like
but its not working
TypeError: Cannot read property '2' of undefined
const editMethod = () => {
let num = Math.floor((Math.random() * 3) + 1);
console.log(num)
let xPath_arr = [
'//android.widget.RadioButton[#text="seat1"]',
'//android.widget.RadioButton[#text="seat2"]',
'//android.widget.RadioButton[#text="seat3"]',
'//android.widget.RadioButton[#text="Notselected"]',
]
return xPath_arr[num];
}
// Then calling in another function like this
const selectseat =() => {
let seatElement = editMethod();
console.log(locator);
}
selectseat();
Note:
Math.random() * 3 it should be because your array contains 4 elements only.

How to filter Tooltip in Leaflet map?

I have a file with serial numbers from 100 to 999. With this file I want to filter out three numbers to display on a map. I have been able to filter both polygons and circle markers but for Tooltips I have not succeeded. This is the code I've been using, how should I fix this?
var po_txt = new L.layerGroup();
$.getJSON("../data/po_txt.geojson", function(json) {
var pointLayer = L.geoJSON(null, {
pointToLayer: function(feature,latlng){
// Filter file
if (feature.properties.Po > 125 && feature.properties.Po < 128 || feature.properties.Po === 129 ) return true
// .bindTooltip can't use straight 'feature.properties.attribute'
label = String(feature.properties.Po)
return new L.CircleMarker(latlng, {
radius: 0,
}).bindTooltip(label, {permanent: true, direction: "center", className: "my1-labels"}).openTooltip();
}
});
pointLayer.addData(json)
pointLayer.addTo(po_txt);
})
I did manage to fix this, needed to put in a function for filter and below code made it work...
var po_txt = new L.layerGroup();
$.getJSON("../data/po_txt.geojson", function(json) {
// Filter
function po_filt (feature){
if (feature.properties.Po > 125 && feature.properties.Po < 128 || feature.properties.Po === 129 ) return true
}
var pointLayer = L.geoJSON(null, {
filter: po_filt,
pointToLayer: function(feature,latlng){
label = String(feature.properties.Po) // .bindTooltip can't use straight 'feature.properties.attribute'
return new L.CircleMarker(latlng, {
radius: 0,
}).bindTooltip(label, {permanent: true, direction: "center", className: "my1-labels"}).openTooltip();
}
});
pointLayer.addData(json)
pointLayer.addTo(po_txt);
})

Resources