How to list points from highest to lowest? - javascript

this code displays the points list randomly ,I want to display points list from the highest to the lowest.
if (command == prefix + 'points') {
if (!message.guild.member(client.user).hasPermission('EMBED_LINKS'))
return message.channel.send(':no_entry: | I dont have Embed Links permission.');
if (!args[1]) {
if (!points)
return message.channel.send(embed);
var members = Object.values(points, null, 5);
var memb = members.filter(m => m.points >= 1);
if (memb.length == 0)
return message.channel.send(embed);
var x = 1;
let pointsTop = new Discord.MessageEmbed()
.setAuthor('Points:')
.setColor('#79758F')
.setDescription(
memb.sort(
(second, first) => first.points > second.points
)
.slice(0, 10)
.map(m => `<#${m.id}> \`${m.points}\``).join('\n')
)
message.channel.send({ embed: pointsTop });

You can use - in Array#sort()
.setDescription(memb.sort((a, b) => a.points - b.points).slice(0, 10).map(m => `${m} \`${m.points}\``).join('\n');

Sort functions should return numbers, not booleans
This is the only part of your code sample that matters:
memb.sort(
(second, first) => first.points > second.points
)
Your custom sort function returns a boolean. That's not how Array.prototype.sort works.
return a negative number if the first argument should sort before the second argument
return a positive number if the second argument should sort before the first argument
return 0 if neither belongs before the other
You probably want this:
memb.sort(
(first, second) => second.points - first.points
)

Related

Sorting array coming from computed property, in a method also sorts the original array (that comes from the computed property)

Im building a vue application for quizzes, I want to display the all the previous results of the person that has taken the quiz. For that I fetch the results from my backend and then pass them to the "view" component with a computed property:
computed: {
allResults() {
return this.$store.state.allResults;
},
I want to also sort out the best results, and the most recent results and display them separately, In order to do that I have the following methods:
bestResults() {
let orderedArray = this.allResults;
orderedArray.sort((a, b) =>
a.score < b.score ? 1 : a.score > b.score ? -1 : 0
);
let half = Math.round(orderedArray.length / 2);
let bestResults = orderedArray.slice(0, half);
return bestResults;
},
recentResults() {
let recentResults = this.allResults.slice(0, 5);
return recentResults;
}
This works, however it sorts the allResults array in a way that shows the scores from highest to lowest, which is what I do in the bestResults() function. This is a problem since I want to display the recentResults based on date, which should show the most recent result on top.
Well, you first sort the array in bestResults(), then use the sorted array in recentResults.
As a solution, you can create a new array with the same elements and sort that, which will leave the original array untouched:
bestResults() {
let orderedArray = [...this.allResults];
orderedArray.sort((a, b) =>
a.score < b.score ? 1 : a.score > b.score ? -1 : 0
);
let half = Math.round(orderedArray.length / 2);
let bestResults = orderedArray.slice(0, half);
return bestResults;
},
recentResults() {
let recentResults = this.allResults.slice(0, 5);
return recentResults;
}

Sorting specific file in top most directory recursively

I'm looking for a way to identify the dist.xml files that are in the top most directory.
Example, I have this list of directory listing,
/opt/pictures/dist.xml
/opt/docs_old/dist.xml
/opt/public/dist.xml
/opt/documents/server/dist.xml
/opt/documents/dist.xml
/opt/documents/web/dist.xml
/opt/documents/class/dist.xml
/opt/documents/lessons/1/dist.xml
/opt/documents/lessons/2/dist.xml
/opt/documents/lessons/3/dist.xml
/opt/documents/lessons/4/dist.xml
/opt/documents/lessons/5/dist.xml
/opt/music/service/day/dist.xml
/opt/music/service/week/dist.xml
/opt/music/service/month/dist.xml
/opt/music/service/month/1/dist.xml
/opt/music/service/month/2/dist.xml
and I'm looking to have this output instead,
/opt/pictures/dist.xml
/opt/docs_old/dist.xml
/opt/public/dist.xml
/opt/documents/dist.xml
/opt/music/service/day/dist.xml
/opt/music/service/week/dist.xml
/opt/music/service/month/dist.xml
I'm trying to achieve this in JS. I thought a simple sort would work.
You could sort thes strings by the count of slashes and then by character and filter the array by having a look to seen pathes.
var data = ['/opt/pictures/dist.xml', '/opt/docs_old/dist.xml', '/opt/public/dist.xml', '/opt/documents/server/dist.xml', '/opt/documents/dist.xml', '/opt/documents/web/dist.xml', '/opt/documents/class/dist.xml', '/opt/documents/lessons/1/dist.xml', '/opt/documents/lessons/2/dist.xml', '/opt/documents/lessons/3/dist.xml', '/opt/documents/lessons/4/dist.xml', '/opt/documents/lessons/5/dist.xml', '/opt/music/service/day/dist.xml', '/opt/music/service/week/dist.xml', '/opt/music/service/month/dist.xml', '/opt/music/service/month/1/dist.xml', '/opt/music/service/month/2/dist.xml'],
result = data
.sort((a, b) =>
a.replace(/[^\/]+/g, '').length - b.replace(/[^\/]+/g, '').length ||
a > b || -(a < b)
)
.filter(
(seen => s =>
(parts =>
!parts.some((_, i, p) => seen.has(p.slice(0, i + 1).join('/'))) &&
seen.add(parts.join('/'))
)
(s.split('/').slice(0, -1))
)
(new Set)
);
console.log(result);
No sorting needed. Put all the paths in a Set, then subsequently filter the array for those paths for which no ancestor exists in the set.
var paths = ['/opt/pictures/dist.xml', '/opt/docs_old/dist.xml', '/opt/public/dist.xml', '/opt/documents/server/dist.xml', '/opt/documents/dist.xml', '/opt/documents/web/dist.xml', '/opt/documents/class/dist.xml', '/opt/documents/lessons/1/dist.xml', '/opt/documents/lessons/2/dist.xml', '/opt/documents/lessons/3/dist.xml', '/opt/documents/lessons/4/dist.xml', '/opt/documents/lessons/5/dist.xml', '/opt/music/service/day/dist.xml', '/opt/music/service/week/dist.xml', '/opt/music/service/month/dist.xml', '/opt/music/service/month/1/dist.xml', '/opt/music/service/month/2/dist.xml'];
const all = new Set(paths);
const result = paths.filter(path => {
const parts = path.split("/");
const filename = parts.pop();
return !Array.from({length: parts.length}, (_, i) => i).some(i =>
all.has(parts.slice(0, i).concat([filename]).join("/"))
);
});
console.log(result);

Discord - showing member join position with specified number

I want to show you which number of users I entered in the argument is the order of joining the server. Like = when i use .join 1 I want to show the 1st member join in to the server. I use
let arr = message.guild.members.filter(a => !a.user.bot).array().sort((b, a) => b.joinedTimestamp - a.joinedTimestamp)
let map = arr.indexOf(sesmi) + 1
this command for showing joing position but im so confused how can i do as i said?
Try this:
// if the first argument is not a number (this message is kind of bad so you can change it)
if (isNaN(args[0])) return message.reply('you must specify what number user you want to get!')
const members = message.guild.members.cache
.filter(member => !member.user.bot)
// sorted is a member on Discord's utility class Collection that doesn't modify the original collection
.sorted((a, b) => a.joinedTimestamp - b.joinedTimestamp)
.array()
// the number user to get
const n = Number(args[0])
// if there are not enough members
if (n > members.length) {
// You only really need this if there is ever going to be only 1 member in the server
// and if you care about grammar. You could also just do
// return message.reply(`there are only ${members.length} members!`)
const plural = members.length !== 1
return message.reply(`there ${plural ? 'are' : 'is'} only ${members.length} member${plural ? 's' : ''}!`)
}
message.channel.send(members[n - 1].user.tag)
I'm assuming args will be an array of strings with the arguments passed into the command (e.g. .join 1 will have the args ['1'].

RxJS Debounce with priority

I'm having trouble coming up with this stream.
What I'm looking for is something like debounceTime but with priority.
So if I have events with the shape { type: 'a', priority: 2 }. These events needs to be debounced by a few seconds but instead of the last event being emitted, the event with the highest priority is emitted.
input stream:
------(a|1)--(b|3)---(c|2)-----------------------(a|1)-----------------
output stream:
-----------------------------------(b|3)---------------------(a|1)-----
I've try looking at other operators like window and filtering through the result for the last event but it's not ideal because window work on a fixed cadence where I want the timer to start on the first event like debouncing does.
You have to store and update the item with the highest priority and map to this highest value which you then pass to debounceTime.
let highest = null;
source$.pipe(
map(v => highest = highest && highest.priority > v.priority ? highest : v),
debounceTime(2000),
tap(() => highest = null)
);
You can create your own operator that does this with the help of defer. defer makes sure that every subscriber gets its own highest variable, as every subscriber will get its own new Observable created by calling the given factory function.
function debounceTimeHighest<T>(dueTime: number, getHighest: (curr: T, high: T) => T): MonoTypeOperatorFunction<T> {
return (source: Observable<T>) => defer(() => {
let highest: T = null;
return source.pipe(
map(item => highest = highest ? getHighest(item, highest) : item),
debounceTime(dueTime),
tap(() => highest = null)
);
});
}
// Usage
source$.pipe(
debounceTimeHighest(2000, (v1, v2) => v1.priority >= v2.priority ? v1 : v2)
)
The code above is Typescript. If you want plain Javascript just remove all the types.
https://stackblitz.com/edit/rxjs-hitqxk
I'll offer the following solution, based around using scan to offer up the highest given priority emission so far for consideration by debounceTime(). Note that scan needs to reconsider new data after every successful debounce, so I use the operator window() to split up the emissions, starting a new observable window after every emission by debounceTime().
Here is the CodeSandbox
And here is some simplified code from the CodeSandbox showing the important bits:
const resetScan$ = new Subject();
source$.pipe(
window(resetScan$),
mergeMap(win$ => win$.pipe(
scan((acc, cur) => acc.priority >= cur.priority ? acc : cur )
)),
debounceTime(debounceDelay),
tap(() => resetScan$.next())
);
You can combine the debounceTime and buffer and filter operator to achieve what you need. I have developed this small example for it.
https://stackblitz.com/edit/typescript-lwzt4k
/*
Collect clicks that occur, after 250ms emit array of clicks
*/
clicks$.pipe(
buffer(clicks$.pipe(debounceTime(1000))),
// if array is greater than 1, double click occured
map((clickArray) => {
document.querySelector('#emittedObjects').innerHTML = (`<div>${JSON.stringify(clickArray)}</div>`);
const sortedArray = clickArray.sort((a, b) => {
return a.priority < b.priority ? 1 : -1;
});
const output = sortedArray.length > 0 ? sortedArray[0] : null;
document.querySelector('#mappedOutput').innerHTML = JSON.stringify(output);
return output;
})
)
.subscribe((obj) => {
const str = obj ? JSON.stringify(obj) : 'NULL';
document.querySelector('#throttledOutput').innerHTML = `<div>THROTTLED: ${str}</div>`;
});

Sort arrays, variables or objects in Javascript

Im new to javascript but I have already made some scripts that really make a difference in my workflow. However I am now embarking on a project that forces me to sort data in a way I dont know howto do in Javascript. I will try to explain what I need to do as if my data was in excel but it isnt, I have only been able to put the data in 4 different arrays:
pagenumber[1,2,3,4,5] //only numbers
zipcode[77889,99887,33667,11122,44559] // only numbers
streetname[Hillroad, Hillroad, Baghdad Street, Hongway, Chinatown] //only letters
roadnumber[55,27,1,13,16] //only numbers
I would like to sort them like this, first by the zipcode, then by the roadname, then by the even roadnumbers descending, then by the odd roadnumbers ascending.
According to this new sorting I want to generate a new pagenumber but I want it to somehow relate to the (old) variable "pagenumber" so I can locate the old page and extract it to a new document with new pagenumbers. I am not asking you guys to write all the code for me but I need a little bit of advice to know firstly if it is possible to do which I think it is, secondly if it is right of me to put the data in four different arrays, thirdly if ther is any (ofcourse) smarter way to save the data so they relate to eachother more closely. Give me your thoughts. Also tips of where and what I should read is appreciated. Thank you all for the answers. However I want to point out that I write my code in Acrobat DC not for the web.
I suppose the items in your arrays are tied. So you should use [{},{},{},{},{}] instead of 4 arrays.
var items = [{pagenumber:1,zipcode:77889,streetname:Hillroad,roadnumber:55},{...},{...},{...},{...}]
Then sort each key-value property one-by-one, like below:
var x= [ {a:2,b:2,c:3}, {a:1,b:1,c:1}, {a:1,b:2,c:3}, {a:2,b:2,c:2} ];
x.sort(function(item1, item2){
var sort_a = item1.a-item2.a;
if (sort_a) return sort_a;
var sort_b = item1.b-item2.b;
if (sort_b) return sort_b;
var sort_c = item1.c-item2.c;
if (sort_c) return sort_c;
})
Or simplify it to be
x.sort(function(item1, item2){
return (item1.a-item2.a) || (item1.b-item2.b) || (item1.c-item2.c);
})
Given the data:
var pagenumber=[1,2,3,4,5]; //only numbers
var zipcode=[77889,99887,33667,11122,44559]; // only numbers
var streetname=['Hillroad', 'Hillroad', 'Baghdad Street', 'Hongway', 'Chinatown']; //only letters
var roadnumber=[55,27,1,13,16]; //only numbers
First, you need to make your data more easily manageable
var data = pagenumber.map(function(itemValue, index) {
return {
pagenumber:itemValue, // == pagenumber[index]
zipcode:zipcode[index],
streetname:streetname[index],
roadnumber:roadnumber[index]
};
});
Then sort it
data.sort(function(a, b) {
if (a.zipzode != b.zipcode) {
// numeric
return a.zipcode - b.zipcode;
}
if (a.streetname != b.streetname) {
// alpha
return a.streetname < b.streetname ? -1 : a.streetname > b.streetname ? 1 : 0;
}
if (a.roadnumber % 2 != b.roadnumber % 2) {
// even before odd
return b.roadnumber % 2 - a.roadnumber % 2;
}
// numeric
return a.roadnumber - b.roadnumber;
});
borrowing from another answer, that can be simplified to
data.sort(function(a, b) {
return (a.zipcode - b.zipcode) || (a.streetname < b.streetname ? -1 : a.streetname > b.streetname ? 1 : 0) || (b.roadnumber % 2 - a.roadnumber % 2) || (a.roadnumber - b.roadnumber);
});
Personally, I don't use the intermediate step when I can avoid it ... so the following is equivalent to bot the map and sort in one chained command
var sortedData = pagenumber.map(function(itemValue, index) {
return {
pagenumber:itemValue,
zipcode:zipcode[index],
streetname:streetname[index],
roadnumber:roadnumber[index]
};
}).sort(function(a, b) {
return (a.zipcode - b.zipcode) || (a.streetname < b.streetname ? -1 : a.streetname > b.streetname ? 1 : 0) || (b.roadnumber % 2 - a.roadnumber % 2) || (a.roadnumber - b.roadnumber);
});
// sorting zipcode in ascending order
zipcode.sort();
// sorting streetname in ascending order
streetname.sort();
// fetching evenroad numbers
var roadnumbereven=roadnumber.filter(function(element, index, array) {
return (element % 2 === 0);
});
// fetching odd roadnumbers
var roadnumberodd = roadnumber.filter(function(element, index, array) {
return (element % 2 !== 0);
});
// sorting even road numbers in ascending order
roadnumbereven.sort();
// sorting odd road numbers in descending order
roadnumberodd.sort(function(a,b){ return b-a; });
// merging roadnumbers(even/odd)
roadnumber = roadnumbereven.concat(roadnumberodd);
console.log(roadnumber);

Categories