How to sort an array of objects by calculated value - arrays

Hello I'm trying to sort an array of objects by value, trought a function that calculates the average of the values in that objects property, which is an array of integers, then sorts it in decreasing order.
// SORT BY SCORE BY MOST SCORED
function sortByScoreDown() {
arrayLivros.sort((a, b) => fullscoreForSort(b._scores) - fullscoreForSort(a._scores));
}
// CALCULATE FULLSCORE
function fullscoreForSort(givenScores) {
let score = 0;
let total = givenScores.length - 1; // -1 BECAUSE BOOK._SCORES STARTS WITH AN ARRAY WITH 0 AS FIRST VALUE FOR SIMPLIFICATION
if (total != 0) {
let summedScore = givenScores.reduce((sum, add) => sum + add);
let score = summedScore / total;
}
return score;
}
// VALUES
newBook1 = {_title: book1,
_scores: [0,100,50]}
newBook2 = {_title: book2,
_scores: [0,100,100]}
newBook3 = {_title: book3,
_scores: [0,50,50]}
newBook4 = {_title: book3,
_scores: [0,30,30]}
arrayBooks = [newBook1, newBook2, newBook3, newBook4];
// EXCPECTED RETURN
arrayBooks = [newBook2, newBook1, newBook3, newBook4];
Thanks in advance.

Related

how to shuffle an array except for the item in the middle?

Iยดm creating a Bingo board and I need that the one in the middle always stays the same even when shuffleing this array:
const bbb = [
"๐Ÿ˜‹",
"๐Ÿ˜",
"๐Ÿคฃ",
"๐Ÿ˜ƒ",
"๐Ÿ˜„",
"๐Ÿ˜…",
"๐Ÿ˜†",
"๐Ÿ˜‰",
"๐Ÿ˜Š",
"๐Ÿ˜Š",
"๐Ÿ˜Ž ",
"๐Ÿคฉ",
"๐ŸŽฏ",
"๐Ÿ˜ถ",
"๐Ÿ˜ซ",
"๐Ÿ˜ด",
"๐Ÿค ",
"๐Ÿ™„ ",
"๐Ÿ˜‘",
"๐Ÿ˜ฏ",
"๐Ÿ˜š",
"๐Ÿ˜ฅ",
"๐Ÿ˜ฎ ",
"๐Ÿ˜›",
"๐Ÿ˜"
];
const data = arrayShuffle(bbb).reduce(
(data, value, index) => ({ ...data, [index]: value }),
{}
);
and then Im maping the array to display the Tiles and create the board like this:
{Object.keys(data).map(id => (
<Tile
key={id}
id={id}
isSet={state.checked[id]}
onToggle={() => toggle(id)}
>
{data[id]}
</Tile>
))}
Remove the middle item from the array initially. Then do the in-place randomizing of items and finally attach the middle item to the array.
This runs in O(n) time complexity where n is the size of your array and you always get a uniform random permutation.
const bbb = [ "๐Ÿ˜‹", "๐Ÿ˜", "๐Ÿคฃ", "๐Ÿ˜ƒ", "๐Ÿ˜„", "๐Ÿ˜…", "๐Ÿ˜†", "๐Ÿ˜‰", "๐Ÿ˜Š", "๐Ÿ˜Š", "๐Ÿ˜Ž", "๐Ÿคฉ", "๐ŸŽฏ", "๐Ÿ˜ถ", "๐Ÿ˜ซ", "๐Ÿ˜ด", "๐Ÿค", "๐Ÿ™„", "๐Ÿ˜‘", "๐Ÿ˜ฏ", "๐Ÿ˜š", "๐Ÿ˜ฅ", "๐Ÿ˜ฎ", "๐Ÿ˜›", "๐Ÿ˜", ];
const getRandomInt = (min, max) => {
min = Math.ceil(min);
max = Math.floor(max);
return Math.floor(Math.random() * (max - min)) + min;
};
const arrayShuffleInplaceExceptMiddle = (A) => {
const middle = A.splice(A.length/2, 1);
const n = A.length;
const middleIndex = Math.floor(n / 2);
for (let i = 0; i < n; i++) {
let swapIndex = getRandomInt(i, n);
let a = A[i];
A[i] = A[swapIndex];
A[swapIndex] = a;
}
A.splice(n/2, 0, ...middle)
};
// test runs
Array.from({length: 10}, () => {
arrayShuffleInplaceExceptMiddle(bbb);
console.log(bbb.join(""));
})
Just shuffle the array normally, but remove the the value before the shuffle and insert it back afterward:
/**
* Durstenfeld shuffle
*
* - https://stackoverflow.com/a/12646864/438273
* - https://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle#The_modern_algorithm
*
* #param {unknown[]} array
*/
function shuffleArray (array) {
for (let i = array.length - 1; i > 0; i--) {
const j = Math.floor(Math.random() * (i + 1));
[array[i], array[j]] = [array[j], array[i]];
}
}
/**
* Like a normal shuffle, but for a bingo board
*
* #param {unknown[]} array
*/
function bingoShuffle (array) {
const index = Math.floor((array.length - 1) / 2);
const [value] = array.splice(index, 1);
shuffleArray(array);
array.splice(index, 0, value);
}
// Let's keep the board small for this demo:
const board = [
"๐Ÿ˜Š",
"๐Ÿ˜Š",
"๐Ÿ˜Ž",
"๐Ÿคฉ",
"๐ŸŽฏ",
"๐Ÿ˜ถ",
"๐Ÿ˜ซ",
"๐Ÿ˜ด",
"๐Ÿค",
];
console.log(board.join(' '));
// Shuffle it a few times and look at the results:
for (let i = 0; i < 10; i += 1) {
bingoShuffle(board);
console.log(board.join(' '));
}
And because you tagged this with reactjs, I'm guessing this is (immutable) state, so you'll need to get a new array when shuffling, like this:
const updatedBoard = bingoShuffle([...board]);
// ^^^^^^^^^^
// Shallow copy into new array so you don't mutate React state

Getting bad state error trying to cast Stream<List<double>> to List<double> in Flutter using dart?

I'm getting a bad state error when I try to cast a Stream<List> to List in Dart using flutter.
This is my function that takes the snapshots and maps them as Weights objects and normalizes the weights so that we can display them on a graph in our app.
List<double> _DeadliftWeightsList(QuerySnapshot snapshot){
List <Weights?> weights = snapshot.docs.map((doc){
Weights(
date: doc.get('date') ?? DateTime.now(),
weight: doc.get('deadLiftWeight') ?? 0);
}).toList();
final List<double> normalized = NormalizedData(weights);
return normalized;
}
This is our Normalize Data function which normalizes the data in a list of weights objects and returns a list of double values of the normalized data:
List<double> NormalizedData (List<Weights?> weights) {
final List<int> array = [];
for(var i = 0 ; i < weights.length; i++) {
array.add(weights[i]!.weight);
}
final lower = array.reduce(min);
final upper = array.reduce(max);
final List<double> normalized = [];
for(var i = 0 ; i < array.length; i++){
normalized.add((array[i] - lower) / (upper - lower));
}
return normalized;
}
This is the function that we use to map the stream of double values from _DeadLiftWeightsList to a list of double values and return that list:
List<double> DLWeights() {
List <double> weights = [];
Stream<List<double>> stream = usersCollection.snapshots()
.map(_DeadliftWeightsList);
stream.listen((weight1) {
for (int x = 0; x < weight1.length; x++){
weights.add(weight1[x]);
}
});
return weights;
}
We're getting a bad state error when we try to cast the data and we don't understand why?

Comparing variable to Math.max(...arr) not returning accurate answer

I'm trying to complete an easy LeetCode question: https://leetcode.com/problems/kids-with-the-greatest-number-of-candies/ but cannot figure out why my code is not working correctly. Here is the question and a correct solution:
Given the array candies and the integer extraCandies, where candies[i] represents the number of candies that the ith kid has.For each kid check if there is a way to distribute extraCandies among the kids such that he or she can have the greatest number of candies among them. Notice that multiple kids can have the greatest number of candies.
Input: candies = [2,3,5,1,3], extraCandies = 3
Output: [true,true,true,false,true]
Here is my current code:
var kidsWithCandies = function(candies, extraCandies) {
let newArr = [];
const max = Math.max(...candies)
for(i=0; i<candies.length; i++) {
let newVal = candies[i] + extraCandies
if (newVal >= max) {
newArr.push('true')
} else {
newArr.push('false')
}
}
return newArr
};
My code is returning [true,true,true,true,true] instead of [true,true,true,false,true].
I've used console.log() to check the values for 'max' and 'newVal' as the loop runs, and they are all correct, so there must be something wrong with my if statement, but I can't figure out what.
Thank you for your help!
You've answered your own question. Nonetheless, this'd also pass on LeetCode:
const kidsWithCandies = (candies, extraCandies) => {
let maxCandies = 0;
const greatest = [];
for (const candy of candies) {
(candy > maxCandies) && (maxCandies = candy);
}
for (let index = 0; index < candies.length; ++index) {
greatest.push(candies[index] + extraCandies >= maxCandies);
}
return greatest;
};

I'm trying to randomize 5 selections from a list of people

This might be less difficult than I'm making it out to be, but I'm trying to make a Discord.JS bot command, that will take however many arguments I have. For example: !randomize 1,2,3,4,5,6,7,8,9,10
And the bot would respond with something like: "I have chosen: 4,2,7,3,9!" Any help?
Current attempt: Not exactly sure what I'm doing.
function shuffleArray(array) {
for (var i = array.length - 1; i > 0; i--) {
var j = Math.floor(Math.random() * (i + 1));
var temp = array[i];
array[i] = array[j];
array[j] = temp;
}
}`
`bot.on('message', async msg => {
if(msg.content === "!add") {
//message.member.user.tag
var msgArray = msg.content.split(" ");
var args = msgArray.slice(1);
var user = args[1];
//if(!args[1]) return msg.channel.send("Please specify an argument!");
if(nameList.includes(user)) {
msg.reply("You're already on the list.")
} else {
nameList.push(args[1]);
msg.channel.send(`${args[1]} has been added to the list!\n Current List:` + nameList);
}
}
if(msg.content === "!bonus") {
if(nameList.length === 0) {
msg.reply("Either the list is empty, or I'm not in the mood!");
} else {
shuffleArray(nameList);
var chosenOne = nameList.pop();
nameList = [];
msg.reply(chosenOne + ' has been chosen! Good luck!');
}
}
if(msg.content === "!list") {
if(nameList.length === 0) {
msg.channel.send("Either the list is empty, or I'm not in the mood!");
} else {
msg.channel.send('The current list:' + nameList);
}
});```
Here's some simple steps to select 5 random elements from an array...
Construct an array of possible selections. In this example I've used names for the first 10 letters of the alphabet. In your code, it'll be the command arguments or predefined nameList.
Make a new array to hold the elements picked.
At some point before #3, you should check to make sure the pool the user has provided is large enough to make 5 selections (Array.length).
Use a for loop to execute the next code multiple times.
Generate a random number representing the index of a selected element (Math.random(), Math.floor()/double NOT bitwise operator).
Push the selection into the array.
Remove the chosen element from the original pool (Array.splice()).
Return the results.
const pool = ['Albert', 'Bob', 'Charlie', 'David', 'Edward', 'Francis', 'George', 'Horacio', 'Ivan', 'Jim'];
const selected = [];
for (let i = 0; i < 5; i++) {
const num = ~~(Math.random() * pool.length);
selected.push(pool[num]);
pool.splice(num, 1);
}
console.log(`I have chosen: ${selected.join(', ')}`);
Take this example and manipulate it within your code to suit your purpose.

Problems with includes() function and array comparsion

As a part of whole procedure, I want to compare user's input (as array) with union of two randomly given arrays. I can not use array.sort() and comparison of arrays element by element, because it's enough to have just one different element in input array and after sorting more than just one element will be identified as "wrong one" (example: array "union" after sorting = [11,13,17,18], array "upis" (user's input) after sorting = [7,11,13,18] so if I compare element by element, which I've tried in original code, all first three elements are identified as wrong...)
That's why I've switched to array.includes() and I've spend last 5.5 hours trying to find where am I wrong and just can't find it so I'm going slightly mad... In few hours I'm supposed to be at work but I'm losing my mind because of this...
THE PROBLEM IS WITHIN checkInput() FUNCTION... The code just won't and won't recognize input elements (array "upis") within "union" array... Can't figure out why???
Any help more then appreciated!
<script>
//----------- 1.) Kreiraj dva nasumiฤna niza i uniju -----------
var arrA = []; //od 3 do max 6 ฤlanova
var arrB = []; //od 2 do max 5 ฤlanova
while (arrA.length < Math.floor(Math.random() * 4) + 3) {
var randomnumber = Math.floor(Math.random() * 20) + 1;
if (arrA.indexOf(randomnumber) > -1) continue;
arrA[arrA.length] = randomnumber;
}
while (arrB.length < Math.floor(Math.random() * 4) + 2) {
var randomnumber = Math.floor(Math.random() * 20) + 1;
if (arrB.indexOf(randomnumber) > -1) continue;
arrB[arrB.length] = randomnumber;
}
var union = [...new Set([...arrA, ...arrB])];
document.write("A = " + arrA + "<br>");
document.write("B = " + arrB + "<br>");
//----------- 2.) Funkcija za dodavanje text box-ova -----------
function addFields() {
// Broj text box-ova koje treba kreirati
var number = union.length;
// <div> u koji ฤ‡e se dinamiฤno dodati text box-ovi
var container = document.getElementById("container");
// Obriลกi prethodni zapis u <div>
while (container.hasChildNodes()) {
container.removeChild(container.lastChild);
}
// Tekst A U B
//container.appendChild(document.createElement("br"));
container.appendChild(document.createTextNode("A โˆช B = "));
for (i = 0; i < number; i++) {
// Kreiraj <input> element i definiraj stil
var input = document.createElement("input");
input.type = "text";
input.id = "element" + i;
input.style.width = 25;
container.appendChild(input);
// Dodaj zarez poslije svakog input box-a, osim posljednjeg
if (i < number - 1) {
container.appendChild(document.createTextNode(", "));
}
}
// Pokaลพi gumb Provjeri
document.getElementById("provj").style.visibility = "visible";
}
//----------- 3.) Provjera upisa -----------
function checkInput() {
var upis = [];
var greske = [];
// Pohrani upis u niz
for (i = 0; i < union.length; i++) {
var privr = document.getElementById("element" + i).value;
upis.push(privr);
}
for (i = 0; i < upis.length; i++) {
// ako je neko polje nepopunjeno, obavijesti i prekini petlju
if (upis[i] === "") {
alert("Treba upisati sve ฤlanove unije skupova!");
greske = [];
//npr. prva dva upisa kriva, ostala polja nepopunjena - iako ima
//praznih polja, prekida se procedura ali se kod prva dva upisa
//popunio niz greลกke i onda ฤ‡e ih pokazati
break;
}
// u protivnom
else {
var n = union.includes(upis[i]);
alert(upis[i] + " " + n);
if (n === false) {
greske.push(upis[i]);
} else {
//niลกta
}
}
}
if (greske.length > 0) {
alert("Krivo upisani ฤlanovi: " + greske);
}
}
</script>
<div id="container">
<button onclick="addFields()">Upiลกi ฤlanove unije</button>
</div>
<button id="provj" style="visibility:hidden" onclick="checkInput()">Provjeri</button>
You are comparing numbers with strings. Just add + to the includes parameter:
var n = union.includes(+upis[i]);
This will force the string to be unboxed as a number and your includes will work as expected.
You other option is to convert those strings to numbers and then no unboxing will be needed.

Resources