Pushing unique numbers within a range to an array in Javascript - javascript

I am trying to insert numbers from 1 to 15 into an array.
And here is the code:
<html>
<head></head>
<body>
<button id="myBtn" value="HELLO">HELLO</button>
<script type="text/javascript">
var btn = document.getElementById("myBtn");
var num = null;
btn.addEventListener('click', function() {
var questions = new Array();
num = Math.floor(Math.random() * 14 + 2);
questions.push(num);
for (var i = 1; i <= 15; i++) {
num = Math.floor(Math.random() * 14 + 2);
if (questions.indexOf(num) !== -1) {
alert(num + " Exists in array. So not pushing it");
} else {
alert(num + " is not found. So pushing it");
questions.push(num);
}
console.log(questions);
}
alert(questions);
})
</script>
</body>
</html>
If you run this with the console open. You will notice that though a number is not in the array the in operator still discards the number without pushing. Can I know why and how to correct this?
And also is there any better way to insert x number of numbers in random order each time.

You should not use in operator with Arrays. What you should have done is
if (questions.indexOf(num) !== -1) {
When you use in with an Array, it will not check the values but the indices of the Array. That is why your code fails.
Please check this answer of mine to know more about, why you should not use in operator with Arrays.
The best way to generate N unique random numbers is to, generate the list of numbers and then shuffle them, like this
function getRandomNumbers() {
var rand, index = 0,
array = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15];
array.forEach(function(value) {
rand = Math.floor(Math.random() * ++index);
array[index - 1] = array[rand];
array[rand] = value;
});
return array;
}
console.log(getRandomNumbers());
This is adopted from the _.shuffle function of Underscore.js library, which shuffles the list of data with Fisher-Yates Shuffle algorithm.

the in operator works on objects, so you're really checking to see if your array has an index, not a value.

Related

Generate an array of unique N random numbers which if all numbers summed up equal to N

Assume that N = 3, I want to make a function to generate 3 unique random numbers which if all numbers summed up will equal to 3. For example:
numbers = [1, 0, 2]
numbers = [2, -4, 5]
I already have my own solution in JavaScript below:
let i = 0;
let arr = []
function getRandomInt(number) {
return Math.floor(Math.random()*(number*2)) - number;
}
function generateArray(i, arr, number) {
let lastIndex = number-1;
while (i < lastIndex) {
let randomNumber = getRandomInt(number);
if (arr.indexOf(randomNumber) > -1) {
continue;
} else {
arr[i] = randomNumber;
}
i++;
}
let summed = arr.reduce((a, b) => a+b);
let lastNumber = number - summed;
if (arr.indexOf(lastNumber) > -1) {
return generateArray(lastIndex-1, arr, number);
} else {
arr[lastIndex] = lastNumber;
return arr;
}
}
But I still have a problem with the last index that tends to deviate quite a lot. For example with N = 10, I could have a result like this one below:
numbers = [2, -1, 3, 4, -4, 0, -5, -8, -6, 15]
I wonder if you guys have a much better solution with also a better performance. Thank you!
Here's a snippet that first fills an array with N unique numbers in a range between -N and N.
Then replaces the last value in the array so that the total = N.
When that recalculated final value is already part of in the array, then the function recurses.
To avoid that the last value isn't unique.
And it also recurses when that final value deviates to much.
function getArrayRandomNumbersInRange(min, max, N) {
let arr = [];
while(arr.length < N){
let num = Math.floor(Math.random() * (max - min + 1)) + min;
if(arr.indexOf(num) > -1) continue;
arr[arr.length] = num;
}
let total = arr.reduce(function(accum, val) {return accum + val});
let lastElem = arr[arr.length-1] - total + N;
if(lastElem < min || lastElem > max || (total !== N && arr.indexOf(lastElem) > -1)) {
//console.log(lastElem + ' -> recurse');
arr = [];
return getArrayRandomNumbersInRange(min, max, N);
}
arr[arr.length-1] = lastElem;
return arr;
}
function getArrayRandomNumbers(N){
return getArrayRandomNumbersInRange(-N, N, N);
}
function sumArray(arr){
return arr.reduce(function(accum, val) {return accum + val})
}
let randomUniqueArray = getArrayRandomNumbers(5);
console.log("Total:\t" + sumArray(randomUniqueArray));
console.log(randomUniqueArray);
EDITED: (I thought about this some more, and think I found an even better way, described below)
Here's what I came up with. This makes the list appear more random, and while there may be a few elements that deviate more than others, but the elements that do could be from any index. It only requires one small change.
You have:
let randomNumber = getRandomInt(number);
Replace this with:
let randomNumber = getRandomInt(number) + i - currentSum;
where currentSum is just a rolling sum of the array, and i is an incrementing variable that starts at zero and increments one every pass through, both of which you would update in the else block of the while loop. (In other words, this would replace the summed variable you have as this would keep track of the sum as the array is generating random numbers). What this change aims to do is to normalize the random number to not have the sum go to far from the what the rolling some is supposed to be around. To sum n numbers to add to n, the 'trivial' solution would be to have every number be 1 (i.e. the rolling sum is just the index of the array). What the above code change does is create a random number that generates random numbers around the expected rolling sum I just described. Thus, if I were to run the code a million times, the average value of every value in the array would be 1, which is perfect with regards to wanting a list as you described. I tested this method in Java real quick and it seems to do what you want, so I hope this 'quick fix' helps.
Another idea (I did not test this one though) to further reduce deviation would be to, in addition to the above change, make the generateRandomInt() function generate numbers in a smaller bound, as right now this function generates numbers with a range of 2 * number, which could produce bigger numbers than you want.
Here are a few test arrays I got when I ran my the changed code (with number = 10):
[-3, 10, 0, -4, -1, 6, -5, 5, -7, 9]
[-6, -2, 4, 6, -8, 8, 3, -4, 7, 2]
[-2, 4, -10, 1, 6, 13, -3, -6, 12, -5]
I hope you get the idea of this; hope this helps!
P.S. I believe the code you posted should have the i++ command inside the else block, as otherwise you might not fill up the entire array.

generate number sequence from consecutive number

I have a scenario where I am getting the consecutive numbers 0,20,40,60,80...
I want to generate 1,2,3,4,5
If I get 0 then generate 1
If 20 then generate 2 and so on..
right now I am doing like :
function generateSequence(consecutiveSequence)
{
if(consecutiveSequence === 0)
{
console.log(1)
}
else
{
console.log(consecutiveSequence / 10);
}
}
But this doesn't give me correct sequence
Can anyone please help?
Based on the desired result this would work in the given case:
var array = []; // Global array
function generateNumber(item) { // function called on every item
array[array.length] = array.length + 1; // array.length will be longer each iteration
console.log(array);
}
var num = [0, 20, 40, 60, 80];
num.forEach(function (e) {
generateNumber(e);
});
I don't really get how the sequence is supposed to work though, the first two numbers are generated right by your algorithm, the others would need a (x / 2) for it to work...
You can simply use forEach loop like this:
var arr = [0,20,40,60,80];
arr.forEach((element, index) => {
arr[index] = index + 1;
});
console.log(arr); // [1, 2, 3, 4, 5]

Javascript - Function for each which sums and multiplies every int in array

Javascript is something new for me, and we have to do homework.
I have created new array:
var numbers = [1,2,3,4,5,6];
And with function forEeach I should achieve result like in console.log:
console.log(numbers[0]*numbers[1]+numbers[0]+numbers[1]);
I've tested many things, but I don't have any idea how to pull out signle init...
I know it should be simple, but I've stucked.
Thanks for help!
From your question looks like your problem is interacting with the current element of the forEach loop.
var numbers = [1,2,3,4,5,6]
// this will print every number in the array
// note that index numbers are not needed to get elements from the array
numbers.forEach(function(num){
console.log(num)
})
Now, if what you're trying t achieve is sum and multiply every int (as stated in the question title), you could do it like this
var numbers = [1,2,3,4,5,6]
var sumResult = 0
var multiplicationResult = 1
// the function will be evaluated for every element of the array
numbers.forEach(function(num){
sumResult += num
multiplicationResult *= num
})
console.log('Sum', sumResult)
console.log('Multiplication', multiplicationResult)
However, a more appropiate approach could be obtained by using reduce like this:
var numbers = [1,2,3,4,5,6]
var sumResult = numbers.reduce(function(result, num){
return num+result
}, 0)
var multiplicationResult = numbers.reduce(function(result, num){
return num*result
}, 1)
console.log('Sum', sumResult)
console.log('Multiplication', multiplicationResult)
Hope this helps.
More info:
Reduce # MDN
ForEach # MDN
To pull out a single number for the provided array you using the indexer/bracket notation which is specifying a number (length of array - 1) in brackets, like below:
var numbers = [1, 2, 3, 4, 5, 6];
numbers[0]; // selects the first number in the array
numbers[1]; // selects second number etc.
To sum up the numbers using forEach, simply do:
var sum = 0;
numbers.forEach(function(number) {
sum += number; // add number to sum
});
forEach goes through all the numbers in the numbers array, passing in each number to the function defined and then adds the number to the sum variable.
If you want your results, use map(). Unlike forEach(), map() will always return results in a new array. It wasn't very clear as to what expression you are expected to use or what the result of said expression should be so this demo will do the following on each iteration:
A = current value * next value
B = current value + next value
C = A + B;
Demo
const num = [1, 2, 3, 4, 5, 6];
let arr = num.map(function(n, idx, num) {
let next = num[idx + 1];
if (!next > 0) {
next = idx + 2;
}
let subSUM = n + next;
let subPRD = n * next;
let subRES = subPRD + subSUM;
return subRES;
});
console.log(arr);

Javascript - Remove elements from an array / sum elements in an array above a certain value

(1)
I have here an array that is a mix of strings and ints:
var newArr = [ 22, 7, "2761", 16, "91981", "37728", "13909", "247214", "8804", 6, 2 ]
My ultimate goal is to remove the values that are ints, and add the other values.
One way I tried to achieve this was to first convert all to ints:
for (element in newArr) {
newArr[element] = parseInt(newArr[element], 10);
}
Is this the best way to do that?
It seems to output an array of ints like this:
var newArr = [ 22, 7, 2761, 16, 91981, 37728, 13909, 247214, 8804, 6, 2 ];
(2)
Then I would like to only sum elements in newArr that are above the value of 30.
This is my code:
var newArr = [ 22, 7, 2761, 16, 91981, 37728, 13909, 247214, 8804, 6, 2 ];
for (element in newArr) {
if (newArr[element] > 30) {
sum += newArr[element];
}
}
It doesn't seem to be working. Please help.
(3)
A final question is:
How could I just eliminate the ints from newArr in step (1), as this would negate the need for the other code, I guess.
A simple solution using only javascript syntax (no jquery) would be appreciated.
(unless the overwhelming consensus is that jquery would be a better option)
Thanks Javascript Ninjas!
First, you might want to look into Array.map. This will allow you to convert them all to ints.
var result = newArr.map(function(x) {
return parseInt(x, 10);
});
Then you can use Array.filter to remove any elements less than or equal to 30.
result = result.filter(function(x) {
return x > 30;
});
Finally, you can use Array.reduce to sum them all together.
sum = result.reduce(function(sum, x) {
return sum + x;
}, 0);
There are numerous ways of accomplishing this but I like this approach because you can chain it together.
var sum = newArray.map(function(x) {
return parseInt(x, 10);
})
.filter(function(x) {
return x > 30;
})
.reduce(function(sum, x) {
return sum + x;
}, 0);
Detect the type then remove them: Here I go through the array, then remove the numbers then go through it again:
var newArr = [22, 7, "2761", 16, "91981", "37728", "13909", "247214", "8804", 6, 2];
for (element in newArr) {
alert(typeof newArr[element] + ":" + newArr[element]);
}
for (var i = newArr.length; i--;) {
if (typeof newArr[i] === "number") {
newArr.splice(i, 1);
}
}
alert(newArr.length);
for (element in newArr) {
alert(typeof newArr[element] + ":" + newArr[element]);
}
I think the best approach to do all this in single iteration would be .
Checking each element with typeof item!="number"
Using Array's Reduce Right :
Sample Use:
[0, 1, 2, 3, 4].reduceRight(function(previousValue, currentValue, index, array) {
return previousValue + currentValue;
});
You can check the previousValue and currentValue with typeof and return the addition if parseInt() return's 30 or more.

Picking 2 random elements from array

What is the most efficient way to select 2 unique random elements from an array (ie, make sure the same element is not selected twice).
I have so far:
var elem1;
var elem2;
elem1 = elemList[Math.ceil(Math.random() * elemList.length)];
do {
elem2 = elemList[Math.ceil(Math.random() * elemList.length)];
} while(elem1 == elem2)
But this often hangs my page load.
Any better solution?
Extra question, how do I extend this to n elements
do NOT use loops and comparisons. Instead
shuffle the array
take first two elements
It can be done using built-in functionality (slice and sort),
var n = 2
randomItems = array.sort(() => .5 - Math.random()).slice(0, n);
http://underscorejs.org/#sample
_.sample(list, [n])
Produce a random sample from the list. Pass a number to return n random elements from the list. Otherwise a single random item will be returned.
_.sample([1, 2, 3, 4, 5, 6]);
=> 4
_.sample([1, 2, 3, 4, 5, 6], 3);
=> [1, 6, 2]
Looking at the source it uses shuffle just like #thg435 suggested.
Your code will hang when the list contains only one item. Instead of using ==, I recommend to use ===, which looks more suitable in this case.
Also, use Math.floor instead of Math.ceil. The length property is equal to <highest index> + 1.
var elem1;
var elem2;
var elemListLength = elemList.length;
elem1 = elemList[Math.floor(Math.random() * elemListLength)];
if (elemListLength > 1) {
do {
elem2 = elemList[Math.floor(Math.random() * elemListLength)];
} while(elem1 == elem2);
}
On what Rob W told you, I'll add that a different solution would be to find a random point and for the second point find a random offset from the point:
var elem1;
var elem2;
var elemListLength = elemList.length;
var ix = Math.floor(Math.random() * elemListLength);
elem1 = elemList[ix];
if (elemListLength > 1) {
elem2 = elemList[(ix + 1 + Math.floor(Math.random() * (elemListLength - 1))) % elemListLength];
}
We add 1 because the current element can't be reselected and subtract 1 because one element has already been selected.
For example, an array of three elements (0, 1, 2). We randomly select the element 1. Now the "good" offset value are 0 and 1, with offset 0 giving the element 2 and offset 1 giving the element 0.
Note that this will give you two random elements with different INDEX, not with different VALUE!
If you want to get n random elements you could create a shuffled version of your list and then return the first n elements of the shuffled array as a result.
If you shuffle the array and splice the number of elements you want to return,
the return value will contain as many items as it can,
if you ask for more items than are in the array.
You can shuffle the actual array or a copy, with slice().
Array.prototype.getRandom= function(num, cut){
var A= cut? this:this.slice(0);
A.sort(function(){
return .5-Math.random();
});
return A.splice(0, num);
}
var a1= [1, 2, 3, 4, 5];
a1.getRandom(2)
>>[4, 2]
If you want to remove the selected items from the original array,
so that a second call will not include the elements the first call returned,
pass a second argument: getRandom(3,true);
window.Memry=window.Memry || {};
Memry.a1= [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
Memry.a1.getRandom(3,true);
>>[5,10,7]
Memry.a1.getRandom(3,true);
>>[3,9,6]
Memry.a1.getRandom(3,true);
>>[8,4,1]
Memry.a1.getRandom(3,true);
>>[2]
While shuffle the array and pick the first two is correct.
You don't need to shuffle the whole array.
Just shuffle the first two!
var arrElm = [1, 2, 3, 4, 5, 6, 7]
var toTake = 2
var maxToShuffle = Math.min(arrElm.length - 1, toTake)
for (let i = 0; i < maxToShuffle; i++) {
const toSwap = i + Math.floor(Math.random() * (arrElm.length - i))
;[arrElm[i], arrElm[toSwap]] = [arrElm[toSwap], arrElm[i]]
}
console.log(arrElm.slice(0, toTake))
basically the same as
https://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle
Except you just quit early when you have enough item shuffled.
You can do something easy like this
const elements = ['indie hackers', 'twitter', 'product hunt', 'linkedIn'];
const randomIndex = Math.floor(Math.random() * elements.length);
const a = elements[randomIndex];
const filteredElements = [...elements].splice(randomIndex, 1);
const b = filteredElements[Math.floor(Math.random() * elements.length)];
a and b will be your random elements.
I find this to be one of the most useful techniques:
var index1 = Math.floor(Math.random() * array.length);
var index2 = Math.floor(Math.random() * (array.length-1));
if index1 == index2 {
index2 += 1;
}
You cannot go out of bounds as index2 cannot get the last element.

Categories

Resources