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.
Related
I want to know how to convert a one-dimensional array into a frequency dictionary with the elements of the array as keys, and their occurrences as values, in JavaScript.
For example, the following Python script creates a list of 1024 random numbers between 0 and 255 and counts the elements as described:
import random
from collections import Counter
sorted(Counter(random.randbytes(1024)).items(), key=lambda x: -x[1])
I can do the same in JavaScript, but much less concise:
var numbers = Array.from({length: 1024}, () => Math.floor(Math.random() * 256))
var counter = Object()
for (let number of numbers) {
if (counter.hasOwnProperty(number)) {counter[number] += 1}
else {counter[number] = 1}
}
Object.entries(counter).sort(([,a],[,b]) => b-a)
How do I make it more concise?
This surprised me: on my Mac, the Map version took 2.7s, and the Object version took 0.6s when testing with 100 million numbers.
(Your original version takes the same time as the Object version in the code below)
const numbers = Array.from({length:10**8},()=>Math.random()*256|0)
let timerStart = new Date()
{
let counter = new Map()
numbers.forEach(n=>counter.set(n,(counter.get(n)??0)+1))
counter = new Map([...counter].sort(([,a],[,b]) => b-a))
}
console.log(`Map version took ${new Date()-timerStart} ms`)
timerStart = new Date()
{
let counter = numbers.reduce((a,c)=>(a[c]=(a[c]??0)+1,a),{})
Object.entries(counter).sort(([,a],[,b]) => b-a)
}
console.log(`Object version took ${new Date()-timerStart} ms`)
Here's an ES6 one-liner to solve the problem, using Array.reduce and the fact that the value of a comma separated list of expressions is the value of the last one:
const numbers = Array.from({length: 1024}, () => Math.floor(Math.random() * 256))
const counter = numbers.reduce((acc, num) => (acc[num] = (acc[num] || 0) + 1, acc), {})
const sorted = Object.entries(counter).sort(([,a],[,b]) => b-a)
console.log(sorted)
You could try using a Map:
var numbers = Array.from({length: 1024}, () => Math.floor(Math.random() * 256))
const map = numbers.reduce((accum, d) => accum.set(d, (accum.get(d) || 0) + 1), new Map());
A quick "improvement" would be to use the ternary statement to make the code more concise.
var numbers = Array.from({length: 1024}, () => Math.floor(Math.random() * 256))
var counter = Object()
for (let number of numbers) {
//If counter has prop number, increment it by one otherwise set to 1
counter.hasOwnProperty(number) ? counter[number]++ : counter[number] = 1;
//Alternatively
//counter[number] = counter.hasOwnProperty(number) ? counter[number] + 1 : 1
}
Object.entries(counter).sort(([,a],[,b]) => b-a)
This question already has answers here:
How to create an array containing 1...N
(77 answers)
Closed 10 months ago.
How do I generate numbers from 1 to 100 in an array without actually typing every single number from 1 to 100 in a way that each number appears only once. I later need to move the generated numbers to an different array but I have that part figured out.
Here is what I have done so far
const arr1 = [1,2,3,4,5,6]
const arr2 = []
const ran = () => {
const index = Math.floor(Math.random() * arr1.length);
if(arr1.length>0)
{
arr2.push(arr1[index])
arr1.splice(index, 1)
const display = document.getElementById('array')
display.innerText = ("\nArray 2 elements " + arr2.toString() + "\n Remaining Array 1 elements" + arr1.toString())
}
else
{
document.write("Array is now empty");
}
}
<button onClick=ran()>click</button>
<span id='array' />
In the above snippet I have displayed elements in array1 as well but I don't need to do it if the numbers are from 1 to 100
you can use map
const array = Array(100).fill(1).map((n, i) => n + i)
console.log(array)
I am creating fake statistics real-time data for that I need to show the number of users available on the website for one game of 5 minutes,
I want to generate random numbers within a range of 1 to 100, but in incremental order. Which means every number that I get should be greater than the previous one.
Expected output:
Output at each function call will be like 1,5,12,25,...,98,100 in randomized and incremental order only.
Thanks in advance.
My code:
randomnumber(fixed,count,range){
return fixed+count*range;
},
function(){
var count = 1;
this.socketData( ({ data }) => {
count++
data.data.totalUsers += this.randomnumber(50,count,Math.abs(Math.floor(Math.random() * (100 - 1) +1)));
}
Assumptions
So, some assumptions to state:
no numbers can be duplicated
numbers must be ascending
numbers must be in range 1 - 100 (inclusive)
Which means we can have anywhere from 1x entry i.e. [100], up to 100 entries [0,1,2,...98,99,100].
So, to implement this strategy, we'll need to:
create X random entries (modify the seed as desired - 100x means we allow for all scenarios, I've chosen to randomise it)
sort the results
remove duplicates
TLDR;
Below is the implementation - works just as well for the range 50 - 200:
// range inclusive
const minRange = 1
const maxRange = 100
const rangePlusOne = maxRange - minRange + 1
// seed = [1 - 100]
const seedNumberOfEntries = parseInt(Math.random() * rangePlusOne) + 1
// generate, sort, unique
console.log([...new Set(
new Array(seedNumberOfEntries)
.fill(0)
.map(() => parseInt(Math.random() * rangePlusOne) + minRange)
.sort((a,b) => a-b)
)]
)
I suggest you create them in one loop and add to an array then sort that array. This should get you a sorted list of incremental random numbers.
You can then just pull 'next' whenever you want the next one.
let numbers = [];
for (let i =0, l = 100; i<l;i++){
let number = Math.floor(Math.random() * 100);
numbers.push(number);
}
numbers.sort(function (a, b) {
return a - b;
});
console.log(numbers);
const from = 0;
const to = 100;
const rand = Number(String(Math.random()).slice(2, 2 + 15));
const num = from + (rand % (to - from - 1)) + 1;
console.log(num);
Hope this will helps you can give range from & to
I implemented the way to generate a list of items with iterable counts with prefix 0. What is the best way to generate such kind of list?
Current behaviour:
const generateList = (length, n, i) => {
let b = n+i
return b.toString().padStart(length.toString().length + n.toString.length, 0)
}
Array(10).fill(null).map((x, i) => generateList(10,2, i))
Output result:
["002", "003", "004", "005", "006", "007", "008", "009", "010", "011"]
Do u have any idea to make it another way?
You could determine the number of characters needed at the start and used the predetermined value to format the output for the array.
function createList(startValue, endValue) {
let
// The minimum output length, for a single digit number, is 2 chars.
outputLength = 2,
testValue = 10,
// Create an empty array which has as many items as numbers we need to
// generate for the output. Add 1 to the end value as this is to be
// inclusive of the range to create. If the +1 is not done the resulting
// array is 1 item too small.
emptyArray = Array(endValue - startValue + 1);
// As long as test value is less than the end value, keep increasing the
// output size by 1 and continue to the next multiple of 10.
while (testValue <= endValue) {
outputLength++;
testValue = testValue * 10;
}
// Create a new array, with the same length as the empty array created
// earlier. For each position place a padded number into the output array.
return Array.from(emptyArray, (currentValue, index) => {
// Pad the current value to the determined max length.
return (startValue + index).toString().padStart(outputLength, '0');
});
}
function createListWithLength(length, startValue = 0) {
return createList(startValue, startValue + length);
}
console.log(createList(2,10));
console.log(createListWithLength(30));
console.log(createListWithLength(10, 995));
Have a look at generators:
function* range(from, to) {
for (var i=from; i<to; i++)
yield i;
}
function* paddedRange(from, to) {
const length = (to-1).toString(10) + 1 /* at least one pad */;
for (const i of range(from, to))
yield i.padStart(length, '0');
}
console.log(Array.from(paddedRange(2, 12)));
You can also inline the loop from range into paddedRange, or you can make it return an array directly:
function paddedRange(from, to) {
const length = (to-1).toString(10) + 1 /* at least one pad */;
return Array.from(range(from, to), i => i.padStart(length, '0'));
}
console.log(paddedRange(2, 12));
The main simplification is that you should compute the padding length only once and give it a denotative name, instead of computing it for every number again. Also ranges are usually given by their lower and upper end instead of their begin and a length, but you can easily switch back if you need the latter for some reason.
Not sure, but maybe something like this
const generateList = length => Array(length).fill('0').map((item, index) => item + index);
console.log(generateList(20));
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(""));