JS Count occurrences in array and sort by highest - javascript

I'm trying to write a vote counting function, I have an array of objects and each object has a property called currentVote which has a userId value. I want to find out which userID has the most votes. Using lodash this is what I got so far:
function countVotes(players) {
return new Promise(function(resolve, reject) {
//votes should be empty, filled it with some sample values
let votes = ['312139659792875521','360445341989863434', '312139659792875521','360445341989863435','1','9999999999999999999999'];
for (let i = 0, j = players.length; i < j; i++) {
votes.push(players[i].currentVote);
}
let tally = _.chain(votes)
.countBy()
.toPairs()
.sortBy(1).reverse()
.map(0)
.value()[0];
resolve(tally);
});
How can I pick a random value IF I have multiple userIds with the same number of votes. At the moment it seems that the smallest ID will always be picked?

Based on your question, I believe your object is as follow, I have used the array method sort to sort the array in descending and picked up the first element. Hope this helps.
let players = [{
"userId":1,
"currentVotes":2220
},
{
"userId":2,
"currentVotes":383830
},
{
"userId":3,
"currentVotes":6894740
},
{
"userId":4,
"currentVotes":6894740
},
{
"userId":5,
"currentVotes":1
}
];
function getHighestVoteByRandowm(players){
let arrSameVotes = [];
let i = 0;
do{
arrSameVotes.push(players[i]);
temp = players[i].currentVotes;
i++;
}while(players[i].currentVotes == temp);
let rndTill = arrSameVotes.length - 1;
let rndVal = Math.round(Math.random() * rndTill);
return arrSameVotes[rndVal];
}
function sortVotes(a,b){
return b.currentVotes - a.currentVotes;
}
let highestVotesPlayer = getHighestVoteByRandowm(players.sort(sortVotes));
console.log(highestVotesPlayer);

You could use _.shuffle and _.first. Maybe something like:
_.chain(votes).countBy()
.groupBy() // added this to get a list of all the ones that have matching vote counts
.toPairs()
.sortBy(0)
.reverse()
.first() // most votes
.last() // get the user ids
.shuffle() // randomize order
.first() // get whatever is first
.value()

Related

Changing the data of the repeater in wix

I'm trying to manipulate the repeater list in Wix. When the user selects the quantity of equipment, that number of forms show up. I got the hang of it when I see it in the console log but when I try to display it on the web, it gives me an error. I've tried reassigning $w("#repeater1").data to newArr(the new data).
Here's my code
$w("#repeater1").hide();
let itemOptions = $w("#quoteDropdown").options
$w("#quoteDropdown").onChange((event) => {
$w("#repeater1").show();
const arrOfValues = []
let newArr = []
let repeaterData = $w("#repeater1").data;
let quantity = Number(event.target.value);
let iterator = repeaterData.values();
for(const value of iterator) {
arrOfValues.push(value);
}
for(let i = 0 ; i < itemOptions.length; i++) {
newArr = repeaterData.slice(0, quantity);
}
if(quantity > newArr.length) {
let newItems = arrOfValues.filter(arr => {
newArr.forEach(na => arr !== na)
})
newArr.push(newItems)
}
console.log("newArr");
console.log(newArr);
// $w("#repeater1").data is the original data from the repeater
// newArr is the altered data from the repeater based on how it appears based on the users' interaction.
// I've tried each one of these
// $w("#repeater1").data = newArr;
// return newArr;
}); // end onChange
If you're trying to assign the array as the data for a repeater, you need to follow some rules. First, it needs to be an array of objects. Second, each object needs to have an _id property.

How to include only updated item on array JavaScript

I wanted to create an array that includes only my last users so I did the following :
// This array should include only the last users
let recived_msg_users = [];
//This function is been called after user insert to the DB
export function chat_afterInsert(item, context) {
let user_date = []
// Users ID
item.userIdb;
// Insertion date
item._createdDate;
user_date.push(item.userIdb)
user_date.push(item._createdDate)
recived_msg_users.push(user_date)
console.log("new msg added", recived_msg_users)
removeOldUsers(recived_msg_users)
console.log("after remove old msg", recived_msg_users)
}
export function removeOldUsers(recived_msg_users) {
var now = new Date();
var nowTimeStamp = now.getTime();
let i;
for (i = 0; i < recived_msg_users.length; i++) {
if (Math.abs(recived_msg_users[recived_msg_users.length - i - 1][1] - nowTimeStamp) < 60000) {
recived_msg_users[recived_msg_users.length - i - 1][1].fruit
} else {
return
}
}
}
After running this code I got the only one array, for example [['1111', '2020-01-01:20:30:31']]
but because every 100 MS a new user insert to my DB I expected to see many arrays items, like this
[['1111', '2020-01-01:20:30:34'],['1111', '2020-01-01:20:30:41'],['1111', '2020-01-01:20:30:71'],['1111', '2020-01-01:20:30:91'], ... ]
I expected array to include items with less than 60 sec from creation, what is wrong?
I think you're looking for the filter() method.
recived_msg_users = recived_msg_users.filter(([user, date]) => Math.abs(data - nowTimeStamp) < 60000);
Note that this doesn't modify the array in place, it returns a new array. So your function will need to return the array, and you'll need to do:
recived_msg_users = removeOldUser(recived_msg_users);

Sorting 2 different list of elements in JavaScript based on value (Name and Surname)

I need some help. I have a multidimensional array containing a sub-array of length 2 ["name","surname"] both as a string value with the first letter capitalized.
The request is to show the first 10 elements of an array at window load. After that, I use a button that load 10 more elements each time is pushed. This functionality works flawlessly.
I am facing 2 problems:
-I have 2 buttons, sort by name and sort by surname. You guessed properly. If "sort by name" btn is pressed you have to sort elements by name and the opposite if "sort by surname" is pressed.
Following functions work well. Sort name and surname. The problem is that when name is sorted, the surname should follow the name to the correct place. Now I can sort both name and surname and the result is to have other full names after sorting.
-The 2nd problem, if we fix the first one, is that if I load 10 or more elements (by pressing "load more" btn) I will need to press sort btn to sort them. I think I should have the initial arrays sorted and then start getting out items from the sorted list. But how do I sort an array with a sub array of ["Name","Surname"]? Thank you in advance
function sortByName(e) {
e.preventDefault();
let itemList = document.getElementById('item-list-two').children;
let names = [];
const itemListArray = Array.from(itemList);
for (let i = 0; i < itemListArray.length; i++) {
names.push(itemListArray[i].innerText.toUpperCase());
names.sort();
}
for (let i = 0; i < itemList.length; i++) {
itemList[i].textContent = names[i].charAt(0) + names[i].slice(1).toLowerCase();
}
}
function sortBySurname(e) {
e.preventDefault();
let itemList = document.getElementById('item-list-three').children;
let surnames = [];
const itemListArray = Array.from(itemList);
for (let i = 0; i < itemListArray.length; i++) {
surnames.push(itemListArray[i].innerText.toUpperCase());
surnames.sort();
}
for (let i = 0; i < itemList.length; i++) {
itemList[i].textContent = surnames[i].charAt(0) + surnames[i].slice(1).toLowerCase();
}
}
Here is a simple example - as you can see when name is sorted the surname follows the name to the correct place. To sort a multidimensional array such as ["Name","Surname"] you just need a compare function that checks the values for the element at position 1 and sorts based on that value. e.g.
const names = [
["Alice", "Smith"],
["Bob", "Jones"],
["Eve", "Chatz"],
["Alice", "Fynn"],
["Alison", "Marks"]
];
const $ = (id) => document.getElementById(id);
function compareSurname(a, b) {
if (a[1] < b[1]) {
return -1;
}
if (a[1] > b[1]) {
return 1;
}
return 0;
}
function log(m) {
$("log").innerHTML = "";
m.forEach(x => $("log").innerHTML += `${x}\n`)
}
$("name").addEventListener("click", () => log(names.sort()));
$("surname").addEventListener("click", () => log(names.sort(compareSurname)));
window.addEventListener('DOMContentLoaded', () => log(names));
<button type=button id=name>Name</button>
<button type=button id=surname>Surname</button>
<pre id=log></pre>
To give some help with the part about loading new data it would require further information!

Function output replaces first two rows of my main JSON string

I have a JSON query and I am using console.log to present it:
var json_data = {"headers":["Month","Value","Number"],"rows":[["2018-10-01 00:00:00.0","one",209],["2018-09-01 00:00:00.0","one",274],["2018-09-01 00:00:00.0","five",183],["2018-10-01 00:00:00.0","five",164],["2018-09-01 00:00:00.0","four",214],["2018-10-01 00:00:00.0","four",192],["2018-09-01 00:00:00.0","three",128],["2018-10-01 00:00:00.0","three",125],["2018-09-01 00:00:00.0","two",199],["2018-10-01 00:00:00.0","two",169],["2018-09-01 00:00:00.0","seven",10541],["2018-10-01 00:00:00.0","seven",6139],["2018-10-01 00:00:00.0","six",169],["2018-09-01 00:00:00.0","six",233]]};
document.getElementById("original").innerHTML = json_data.rows;
<div style="background:yellow; "id="original"></div>
<div style="background:red;" id="output"></div>
And for the value "one" I have two numbers (209 and 274).
I am then using a function to groupby which works fine (output). My problem is that when I use the console.log for the initial json_data query, the first two rows are different. It seems that my function replaced the first two rows with the rows of the output (red). The function is given here:
function initialGroupBy(rows) {
const
rowMap = new Map(),
result = [],
dataTemp = [];
// Iterate over the rows.
rows.forEach(row => {
const
// Create a key, it is the first elements joined together.
key = row.slice(0,1).join();
// Check if the Map has the generated key...
if (rowMap.has(key)) {
// The map has the key, we need to add up the values
const
// Get the value for the current key.
storedRow = rowMap.get(key);
// Add the value of the current row to the row in the map.
storedRow[2] += row[2];
} else {
// The key doens't exist yet, add the row to the map.
rowMap.set(key, row);
}
});
// Iterate over all the entries in the map and push each value with the
// summed up value into the array.
rowMap.forEach(value => {
result.push(value);
});
for (i = 0; i < result.length; i++)
{
var object2 = {"date": result[i][0].slice(0,7), "num": result[i][2]};
dataTemp.push(object2);
}
return dataTemp;
}
A full snippet can be found here (Compare the first two rows of the yellow box from the two snippets):
var json_data = {"headers":["Month","Value","Number"],"rows":[["2018-10-01 00:00:00.0","one",209],["2018-09-01 00:00:00.0","one",274],["2018-09-01 00:00:00.0","five",183],["2018-10-01 00:00:00.0","five",164],["2018-09-01 00:00:00.0","four",214],["2018-10-01 00:00:00.0","four",192],["2018-09-01 00:00:00.0","three",128],["2018-10-01 00:00:00.0","three",125],["2018-09-01 00:00:00.0","two",199],["2018-10-01 00:00:00.0","two",169],["2018-09-01 00:00:00.0","seven",10541],["2018-10-01 00:00:00.0","seven",6139],["2018-10-01 00:00:00.0","six",169],["2018-09-01 00:00:00.0","six",233]]};
function initialGroupBy(rows) {
const
rowMap = new Map(),
result = [],
dataTemp = [];
// Iterate over the rows.
rows.forEach(row => {
const
// Create a key, it is the first elements joined together.
key = row.slice(0,1).join();
// Check if the Map has the generated key...
if (rowMap.has(key)) {
// The map has the key, we need to add up the values
const
// Get the value for the current key.
storedRow = rowMap.get(key);
// Add the value of the current row to the row in the map.
storedRow[2] += row[2];
} else {
// The key doens't exist yet, add the row to the map.
rowMap.set(key, row);
}
});
// Iterate over all the entries in the map and push each value with the
// summed up value into the array.
rowMap.forEach(value => {
result.push(value);
});
for (i = 0; i < result.length; i++)
{
var object2 = {"date": result[i][0].slice(0,7), "num": result[i][2]};
dataTemp.push(object2);
}
return dataTemp;
}
const damn = initialGroupBy(json_data.rows);
document.getElementById("original").innerHTML = json_data.rows;
document.getElementById("output").innerHTML =JSON.stringify(damn);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div style="background:yellow; "id="original"></div>
<br><br>
<div style="background:red;" id="output"></div>
I have tried changing the var to const in many cases. Am I missing a fundamental JavaScript case here?
As your value is an Array object, when you save it in your temporary Map, you're actually using a reference to your original data structure row.
So in the first forEach loop, where you sum the values you're actually changing the original array entry.
The solution is pretty simple, just clone the array:
rowMap.set(key, row.slice());
Another possibility is to use a different array to save the totals.
Here is your code with the fix.
var json_data = {"headers":["Month","Value","Number"],"rows":[["2018-10-01 00:00:00.0","one",209],["2018-09-01 00:00:00.0","one",274],["2018-09-01 00:00:00.0","five",183],["2018-10-01 00:00:00.0","five",164],["2018-09-01 00:00:00.0","four",214],["2018-10-01 00:00:00.0","four",192],["2018-09-01 00:00:00.0","three",128],["2018-10-01 00:00:00.0","three",125],["2018-09-01 00:00:00.0","two",199],["2018-10-01 00:00:00.0","two",169],["2018-09-01 00:00:00.0","seven",10541],["2018-10-01 00:00:00.0","seven",6139],["2018-10-01 00:00:00.0","six",169],["2018-09-01 00:00:00.0","six",233]]};
function initialGroupBy(rows) {
const
rowMap = new Map(),
result = [],
dataTemp = [];
// Iterate over the rows.
rows.forEach(row => {
const
// Create a key, it is the first elements joined together.
key = row.slice(0,1).join();
// Check if the Map has the generated key...
if (rowMap.has(key)) {
// The map has the key, we need to add up the values
const
// Get the value for the current key.
storedRow = rowMap.get(key);
// Add the value of the current row to the row in the map.
storedRow[2] += row[2];
} else {
// The key doens't exist yet, add the row to the map.
rowMap.set(key, row.slice());
}
});
// Iterate over all the entries in the map and push each value with the
// summed up value into the array.
rowMap.forEach(value => {
result.push(value);
});
for (i = 0; i < result.length; i++)
{
var object2 = {"date": result[i][0].slice(0,7), "num": result[i][2]};
dataTemp.push(object2);
}
return dataTemp;
}
const damn = initialGroupBy(json_data.rows);
document.getElementById("original").innerHTML = json_data.rows;
document.getElementById("output").innerHTML =JSON.stringify(damn);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div style="background:yellow; "id="original"></div>
<div style="background:red;" id="output"></div>
A) The const declaration creates a read-only reference to a value. It does not mean the value it holds is immutable -> Link
B) Your problem is that you are actually editing the original object in the initialGroupBy function. Maybe this answer will be helpful.
A different logic applies here and the result is handy:
var json_data = {"headers":["Month","Value","Number"],"rows":[["2018-10-01 00:00:00.0","one",209],["2018-09-01 00:00:00.0","one",274],["2018-09-01 00:00:00.0","five",183],["2018-10-01 00:00:00.0","five",164],["2018-09-01 00:00:00.0","four",214],["2018-10-01 00:00:00.0","four",192],["2018-09-01 00:00:00.0","three",128],["2018-10-01 00:00:00.0","three",125],["2018-09-01 00:00:00.0","two",199],["2018-10-01 00:00:00.0","two",169],["2018-09-01 00:00:00.0","seven",10541],["2018-10-01 00:00:00.0","seven",6139],["2018-10-01 00:00:00.0","six",169],["2018-09-01 00:00:00.0","six",233]]};
function groupBy(accumulator, item) {
const [date,extra,value] = item;
const key = date.slice(0,7);
if(!accumulator[key]){
accumulator[key] = 0
}
accumulator[key] += value;
return accumulator;
}
var damn = json_data.rows.reduce(groupBy,{});
damn = Object.keys(damn).map(function(key){
return {date: key, Value: "Total", num: damn[key]};
})
document.getElementById("original").innerHTML = json_data.rows;
document.getElementById("output").innerHTML =JSON.stringify(damn);
<div style="background:yellow; "id="original"></div>
<div style="background:red;" id="output"></div>

MongoDB Documents : Find number of Repetitions and Sort In Ascending Order

So I'm working on an agent that's supposed get data from MongoDB, iterate through it, and then find the keys which have the same values, and sort that list in ascending order. Basically, find out how many repetitions there are in the documents from Mongo, and then sort it.
So I've gotten to the part where I get repetitions in the data, and count them, but I'm stuck with getting the ascending order part.
The code for getting documents out of mongodb and processing it is as follows.
function matchRoomAndAgent() {
var url = 'mongodb://192.168.10.10:27017';
MongoClient.connect(url, function (err, db) {
db.collection("whiteboardRooms").find({}).toArray(function (err, res) {
var roomsArray = [];
var count = {};
var temp_count = {};
if (err) {
throw err;
}
db.close();
// roomsArray.push(res);
for (var i = 0; i < res.length; i++) {
roomsArray.push(res[i]);
// console.log('agentId: '+ res[i][agentId].agentId);
}
// console.log(roomsArray);
for (var i = 0; i < 15; i++) //supposed to use length of roomsArray
{
var currentAgent = roomsArray[i].agentId;
for (var j = 0; j < 15; j++)
{
if (roomsArray[j].agentId == currentAgent)
{
count[j] = (count[j] || 0) + 1;
temp_count[j] = count[j];
}
}
console.log(temp_count);
}
Also please find attached, a sample pic of the mongodb documents.
MongoDB Documents
Please let me know if you require more information, and I'll do my best to get it. I'm kind of a noob at programming. Sorry!
Thanks in advance for your help :)
At some point you might want to limit the material being grouped, for example by lastUpdateTime between two timestamps and you don't want to drag all that out of the DB just to throw it away. Here's the general shape of the solution:
db.foo.aggregate([
{$match: {agentID: {$ne: " "}}} // guessing this is noise so filter out
// other $match could be used here to further shrink the data...
,{$group: {_id:"$agentID", n:{$sum:1}}}
,{$match: {n: {$gt:1}}} // ignore non-dupes
,{$sort: {_id: 1}} // and finally sort.
]);
So I've figured out the answer to my own problem. Its pretty much got nothing to do with MongoDB.
I basically had an array called roomsArray which contained objects. I used groupBy and map to project these objects to a format I wanted, and then used sort as I would an array, using its length to get the count.
I should have used groupBy() and map() with sort() to get the values I needed.
var groupBy = function (array, key) {
return array.reduce(function(acc,val){
(acc[val[key]] = acc[val[key]] || []).push(val);
return acc;
}, {});
};
var result = groupBy(roomsArray, 'agentId');
// console.log(result);
var mapped = Object.keys(result).map(function(x){
return { agentId : x, rooms: parseInt(result[x].length)}
});
// console.log(mapped);
var sorted = mapped.sort((a,b) => a.rooms - b.rooms);
console.log(sorted);

Categories

Resources