Create a calculated array based on limits [duplicate] - javascript

This question already has answers here:
Does JavaScript have a method like "range()" to generate a range within the supplied bounds?
(88 answers)
Closed 11 months ago.
OK time to pick the hive mind brain.
I am creating a dropdown (well 2 of them) and I need them to do the following
Height from 4'0" to 7'0"
Weight from 100lb to 400lb in 5lb incraments.
What would be the best/easiest way to create this array without having to manually create an array
It just needs to be as simple as
const heights = [
{ id: '', name: '' },
]
I just to not know how to best create it in as few Lines of code or manually creating the array
Same with height in 5lb increments
EDIT: SO people know WHY I am asking this - try doing a google search and enjoy the frustration.

For the weights, you can use the Array.fill function as seen in this answer.
// https://stackoverflow.com/questions/3895478/does-javascript-have-a-method-like-range-to-generate-a-range-within-the-supp
const range = (start, stop, step = 1) =>
Array(Math.ceil((stop - start) / step) + 1).fill(start).map((x, y) => x + y * step)
const weights = range(100, 500, 5).map((x, index) => ({
id: index,
name: x
}))
console.log(weights)
// or with one line of code
const w = Array(Math.ceil((500 - 100) / 5) + 1).fill(100).map((x, index) => ({
name: x + index * 5, id: index
}))
console.log(w)
For the heights, you can use a simple algorithm as a while loop with a condition for the increment
const start = {
integer: 4,
fractionnal: 0
}
const end = {
integer: 7,
fractionnal: 0
}
const heights = []
let index = 1
while (start.integer < end.integer || start.fractionnal <= end.fractionnal) {
heights.push({
id: index,
name: `${start.integer}.${start.fractionnal}`
})
if (start.fractionnal < 11) start.fractionnal += 1
else {
start.integer += 1
start.fractionnal = 0
}
}
console.log(heights)

Related

Decrease length of array - Javascript

I create an array of random and unique numbers from 1 to 51 //[0,1,2,3,4...,51]
i want to take 5 random numbers from that array EXAMPLE //[3,5,27,31,44]
Now i wont to delete that numbers from the principal array so the decrease of array decrease of 5
This is the code i created is:
const filterRandomValue = function (deck) {
const randomNumbers = deck
.sort(() => Math.random() - Math.random())
.slice(0, 5);
return deck.filter((val) => !randomNumbers.includes(val));
};
filterRandomValue(randomUniqueNum(51, 51)) // it returns an array of 46 elements and just for one times it works
I create a button and each time i click it, i wont to decrease the numbers until it will reach a number at least equal of 5 or >= 5, and i don't know how to do it.
Because if i run the functions again it will create a full (51 elements) array.
Anyone can help me??
The issue can be fixed by separating the creation from the editing. Create the array and store it in a block variable. Then you can access that array in your function everytime the button is clicked.
const filterRandomValue = function(deck) {
const randomNumbers = deck.sort(() => Math.random() - Math.random()).slice(0, 5);
return deck.filter((val) => !randomNumbers.includes(val)).sort( (a,b) => +a - +b);
};
const randomUniqueNum = () => {
let x = 0,
d = [];
while (++x < 51) d.push(x)
return d
}
let array = randomUniqueNum()
window.addEventListener('load', () => {
document.querySelector('.extract').addEventListener('click', () => {
array = filterRandomValue(array)
display()
})
display()
})
const display = () => {
document.querySelector('.numbers').innerText = array.join(', ')
document.querySelector('.n').innerText = array.length
}
.numbers{
width:400px;
height:100px;
}
<textarea class='numbers'></textarea>
<p>#array items: <span class='n'></span>
<button class='extract'>extract</button>
Instead of putting randomUniqueNum straight into your filterRandomValue function, try creating an array with randomUniqueNum and then using that.
let myArr = randomUniqueNum(51, 51)
.sort(() => Math.random() - Math.random())
.slice(0, 5);
filterRandomValue(myArr); // array length: 46
filterRandomValue(myArr); // array length: 41
The error is that you are generating a new array each time you call randomUniqueNum.
Though your question is now answered, I think there are some fundamental problems with your code.
The randomUniqueNum function is pointless if you're using 51 unique numbers in a length 51 array. By that logic, the array is just the numbers 1 to 51, or 0 to 50, depending on where you start.
I think you should take a look at the steps you're taking and work out what parts are necessary.

Javascript how to round a whole number up and find its addition value?

Goal
I am at the final stage of scripting a Luhn algorithm.
Problem
Let's say I have a final calculation of 73
How can I round it up to the next 0? So the final value is 80.
And lastly, how can I get the value that made the addition? e.g. 7 is the final answer.
Current code
function validateCred(array) {
// Array to return the result of the algorithm
const algorithmValue = [];
// Create a [2, 1, 2] Pattern
const pattern = array.map((x, y) => {
return 2 - (y % 2);
});
// From given array, multiply each element by it's pattern
const multiplyByPattern = array.map((n, i) => {
return n * pattern[i];
});
// From the new array, split the numbers with length of 2 e.g. 12 and add them together e.g. 1 + 2 = 3
multiplyByPattern.forEach(el => {
// Check for lenght of 2
if(el.toString().length == 2) {
// Split the number
const splitNum = el.toString().split('');
// Add the 2 numbers together
const addSplitNum = splitNum.map(Number).reduce(add, 0);
// Function to add number together
function add(accumalator, a) {
return accumalator + a;
}
algorithmValue.push(addSplitNum);
}
// Check for lenght of 1
else if(el.toString().length == 1){
algorithmValue.push(el);
}
});
// Sum up the algorithmValue together
const additionOfAlgorithmValue = algorithmValue.reduce((a, b) => {
return a + b;
});
// Mod the final value by 10
if((additionOfAlgorithmValue % 10) == 0) {
return true;
}
else{
return false;
}
}
// Output is False
console.log(validateCred([2,7,6,9,1,4,8,3,0,4,0,5,9,9,8]));
Summary of the code above
The output should be True. This is because, I have given the total length of 15 digits in the array. Whereas it should be 16. I know the 16th value is 7, because the total value of the array given is 73, and rounding it up to the next 0 is 80, meaning the check digit is 7.
Question
How can I get the check number if given array length is less than 15?
You could do something like this:
let x = [73,81,92,101,423];
let y = x.map((v) => {
let remainder = v % 10;
let nextRounded = v + (10-remainder);
/* or you could use
let nextRounded = (parseInt(v/10)+1)*10;
*/
let amountToNextRounded = 10 - remainder;
return [nextRounded,amountToNextRounded];
});
console.log(y);
EDIT
As noticed by #pilchard you could find nextRounded using this more simplified way:
let nextRounded = v + (10-remainder);
https://stackoverflow.com/users/13762301/pilchard
I think what you need is this:
var oldNum = 73
var newNum = Math.ceil((oldNum+1) / 10) * 10;;
Then check the difference using this:
Math.abs(newNum - oldNum);

How to iterate on two arrays and produce unique y coordinates

Context: In Sketch, I am writing a plugin to render text on the canvas that shows a vertical list of text and its font size + weight combinations.
[ Uses JavaSCript [
The problem: I cannot figure out how to programmatically increase the Y pos of each layer properly.
Say I have two arrays:
const fontWeights = ['normal', 'bold'];
const fontSizes = ['small', 'medium', 'large'];
I want to generate a vertical list of each combination of fontWeight + fontSize, so it looks like this:
smallNormal
smallBold
mediumNormal
mediumBold
largeNormal
largeBold
(or graphically, see image)
function renderLayers() {
return fontWeights.map((weight, weightsIndex) =>
fontSizes.map((size, sizeIndex) =>
return (
<TextLayer
fontSize={size}
fontWeight={weight}
yPos={ (weightsIndex + sizeIndex) * 100 }
/>
}
That kinda works, except there is a case where:
0 + 0 * 100 = 0
0 + 1 * 100 = 100
1 + 0 * 100 = 100 // <-- that should be 200
All I really want to do is offset each iteration by a fixed amount. I am sure that there's some logic / mathematical way to do this, but i am stuck.
Help would be great thanks!
You can just keep an external variable to store the yPos:
function renderLayers() {
let y = 0;
return fontWeights.map((weight) =>
fontSizes.map((size) => {
y = y + 100;
return <TextLayer fontSize={size} fontWeight={weight} yPos={y} />;
})
);
}
The map index might not be the best for this job because it alternates between 0 and the length of the array - 1, so it's really not what you want. You need some variable on the outside of the maps that can store the "count" of both iterations combined.
I've added a new line, but you could also just do:
return <TextLayer fontSize={size} fontWeight={weight} yPos={y += 100} />;

How to return a string based on correspondent values summed from an array of strings

As the topic states what is the best way to make it so that when you pass an array of emotions/values, to show the closest value based on a numeric mapping in javascript?.
Assume that 'Glad' is the same thing as 'Happy', and 'Down' is the same thing as 'Sad'. Ithe code I've tried seems incredibly lengthy and gets bloated if I add more emotions/states (i.e. Angry). Aside from the emotions array, any new functions and data structures and variables can be changed/introduced.
for example, I can get a list of emotions:
let emotions = ['Happy','Happy','Sad','Glad','Angry'];
Now I want to return a string that reflects what the 'closest' emotion based on these 5 emotions.
For a better example, let's assume the values correspondent to each emotion is:
Angry = 1, Happy = 2, Sad = 3
I was trying something like:
var numb = 0;
for (var i = 0; i < emotions.length; i++) {
if (numb == 'Angry')
numb += 1;
if (numb == 'Happy' || numb == 'Glad')
numb += 2;
if (numb == 'Sad' || numb == 'Down')
numb += 3;
}
var average = numb / emotions.length;
// check which number is closer to
if (average < 1.5)
return 'Angry';
if (average >= 1.5 && < 2.5)
return 'Happy';
if (average > 2.5)
return 'Sad';
if (average == 1.5)
return 'Angry or Happy';
if (average == 2.5)
return 'Happy or Sad';
My expected result based on this list of emotions is:
2(*Happy*) + 2(*Happy*) + 3(*Sad*) + 2(*Happy|Glad*) + 1(*Angry*) = 10
Then divide by 5 (the emotions array length), resulting in 2.
So the result that should be returned, as string, is "Happy".
Let's say I added a fourth type of emotion/feeling... I would be adding more and more of these conditions, and it gets more complicated in the logic checking for the ranges of the numbers.
I am looking at the list of emotions as a whole, and trying to come up with an overall emotion that represents the whole list.
What is the best way to do this so that the code looks clean and I can support more states without having the lines of code become too long?
What about something like this:
Having two object constants:
emotionsValues: Here you assing a value to each emotion you want, like a score to each.
emotionsRank: Here is the final result of each value, based on average you'll get the result from here.
Now:
Receive the emotions array by parameter.
reduce it based on the value of each mapped emotion (using emotionsValues).
Get the average
See if the floor value + ceil value divided by 2 is equal to the number itself (it means its exactly the half), so use the "emotion or emotion".
OR, if not the half, then round to the nearest and get the correct emotion. Don't forget to check if average is below 1 or bigger the the last rank (3 in this case)
const emotionsValues = {
"Angry": 1,
"Happy": 2,
"Glad": 2,
"Sad": 3,
"Down": 3,
}
const emotionsRank = {
1: "Angry",
2: "Happy",
3: "Sad",
}
function getEmotion(arrayEmot) {
let numb = arrayEmot.reduce((acc, v) => Number(emotionsValues[v]) + acc, 0);
let avg = numb / arrayEmot.length;
let min = Math.floor(avg)
let max = Math.ceil(avg)
if ((min + max) / 2 == avg && min != max) {
return emotionsRank[min] + " or " + emotionsRank[max]
} else {
let rounded = avg < 1 ? 1 : avg > 3 ? 3 : Math.round(avg);
return emotionsRank[rounded];
}
}
let emotionsTest = ['Happy', 'Happy', 'Sad', 'Glad', 'Angry'];
console.log(getEmotion(emotionsTest))
let emotionsTest2 = ['Happy', 'Happy', 'Sad', 'Sad'];
console.log(getEmotion(emotionsTest2))
You may create the function emo to value and its reciprocal one: value to emotionS:
Then you map every emotions found in array to its value
do your standard mathematical stuff
and get back to emotions via the reciprocal function
const emoToValue = {
Glad: 1,
Happy: 1,
Sad: 2
}
const valueToEmos = Object.entries(emoToValue).reduce((acc, [emo, val]) => {
acc[val] = acc[val] || []
acc[val].push(emo)
return acc
}, {})
//compute the average:
function avgEmotion (emotions) {
if (emotions.length == 0) return ''
const avg = emotions.reduce((s, em) => s + emoToValue[em], 0) / emotions.length
return valueToEmos[Math.round(avg)].join(' or ')
}
console.log('str', avgEmotion(['Happy', 'Happy', 'Sad', 'Happy'])) //Glad or Happy
console.log('str', avgEmotion(['Happy', 'Happy', 'Sad', 'Sad'])) //Sad
This function explicitly checks for the "mid" case and also for out of range values (since it's based on indices):
function getEmotion(emotions, value) {
// Out of range
if ( value > emotions.length ) return emotions[emotions.length - 1];
if ( value < 1 ) return emotions[0];
// Determine if decimal is .5
let mid = value % 1 === .5;
// Round the value to the nearest integer
let rounded = Math.round(value);
return mid ? `${emotions[rounded - 2]} or ${emotions[rounded - 1]}` : emotions[rounded - 1];
}
Output:
let emotions = ['Happy', 'Happy', 'Sad', 'Glad', 'Angry'];
console.log(getEmotion(emotions, -23)); // Happy
console.log(getEmotion(emotions, 0)); // Happy
console.log(getEmotion(emotions, 1)); // Happy
console.log(getEmotion(emotions, 2.43)); // Happy
console.log(getEmotion(emotions, 2.5)); // Happy or Sad
console.log(getEmotion(emotions, 3.1)); // Sad
console.log(getEmotion(emotions, 155.65)); // Angry
You could create a set of indices and get the values by filtering with the index.
function getEmotion(emotions, value) {
var values = new Set([value + 0.5, value - 0.5, Math.round(value)]);
return emotions.filter((e, i) => values.has(i + 1)).join(' and ');
}
console.log(getEmotion(['Happy', 'Sad', 'Glad', "Angry"], 1));
console.log(getEmotion(['Happy', 'Sad', 'Glad', "Angry"], 1.5));
console.log(getEmotion(['Happy', 'Sad', 'Glad', "Angry"], 1.7));

a better way to do random sampling with a probability distribution? [duplicate]

This question already has answers here:
Generate A Weighted Random Number
(14 answers)
Get random element from array with weighted elements [duplicate]
(2 answers)
Closed 5 years ago.
I want to choose random items from an array but with certain probability distributions.
currently I do:
myarray =[5,5,5,95]
which gets me a 75% chance of getting a 5 and 25% chance of getting a 95.
I have a lot more numbers though and it takes too much time to write out all those numbers, is there a faster/better way to do this?
You can have an array with objects that contain any value, and a weight property that's a number.
// data
const samples = [
{ value: 5, weight: 75 },
{ value: 95, weight: 25 }
];
// requested method
function randomSample (samples) {
// [0..1) * sum of weight
let sample =
Math.random() *
samples.reduce((sum, { weight }) => sum + weight, 0);
// first sample n where sum of weight for [0..n] > sample
const { value } = samples.find(
({ weight }) => (sample -= weight) < 0
);
return value;
}
// demo
const counts = { 5: 0, 95: 0 };
Array
// take a million random samples
.from({ length: 1000000 }, () => randomSample(samples))
// count each sample
.forEach(value => { counts[value]++; });
console.log(counts);
The data does not have to be in any particular order, nor do the weights need to add up to any particular sum.
function weightedChoice(array, weights) {
let s = weights.reduce((a, e) => a + e);
let r = Math.random() * s;
return array.find((e, i) => (r -= weights[i]) < 0);
}
let randomArray =
Array.apply(null, Array(32)).
map(() => weightedChoice([5, 95], [75, 25]));
console.log(JSON.stringify(randomArray));
EDIT: Patrick was a bit faster than me, so I'll endorse his answer, and I'll just add that you don't absolutely need the sum to be 1, you can normalise the weight by finding out the sum by yourself.
EDIT EDIT: If you are really worried about performance in the case of needing many random values with the same weights, this would do better (by precalculating as much as possible):
class WeightedSampler {
constructor(elements, weights) {
this.total = 0;
this.elements = Array.from(elements);
this.cweights = weights.map(weight => this.total += weight);
}
get() {
let random = Math.random() * this.total;
return this.elements.find((element, index) => random < this.cweights[index]);
}
}
const sampler = new WeightedSampler(["M", "I", " "], [3, 9, 1]);
let randomArray = Array.apply(null, Array(32)).map(() => sampler.get());
console.log(randomArray.join(""));

Categories