I want to pick random number of inputs randomly in an array of input elements..
If i use the below method i Can get one random item
jQuery.jQueryRandom = 0;
jQuery.extend(jQuery.expr[":"],
{
random: function(a, i, m, r) {
if (i == 0) {
jQuery.jQueryRandom = Math.floor(Math.random() * r.length);
};
return i == jQuery.jQueryRandom;
}
});
$("input:random").prop('id')
But I want random number i=of items to be picked randomly in an array.
You can use jQuery's .filter() method with a function:
$('div').filter(function(){
return (Math.round(Math.random()) == 1);
}).css({background: 'red'});
jsFiddle example
You currently are checking if the index is equal to the random number. Maybe it´s better to generate a random number for each input and check if its bigger then 1 or smaller. So randomize a number between 0 and 2. something like:
jQuery.extend(jQuery.expr[":"],
{
random: function(a, i, m, r) {
return Math.random() > 0.5;
}
});
alert( $("input:random").length );
Also if you get a prop from an element, it will only get it from the first one.
I'm proposing a non-jQuery answer to you question on how to get count elements randomly from an array arr
var pickRandom = function (arr, count) {
var out = [], i, pick, clone = arr.slice(0, arr.length);
for (i = 0; i < count; i ++) {
pick = Math.floor(Math.random() * clone.length);
if (clone[pick] !== undefined) {
out.push(clone[pick]);
clone.splice(pick, 1);
}
}
return out;
};
This function makes sure that the original array is preserved and handles undefined values correctly
Related
I want to set a matrix with random numbers.
I used a function to create a 0 matrix first, then loop through every cell and assign a random number to it.
function getRandomArbitrary(min, max) {
let value = Math.random() * (max - min) + min;
if (value === 0)
return getRandomArbitrary(min, max);
return value;
}
function matrix(m, n, d) {
return Array.apply(null, new Array(m)).map(
Array.prototype.valueOf,
Array.apply(null, new Array(n)).map(
function() {
return d;
}
)
);
}
let weight_1 = matrix(4, 3, 0);
for (let i = 0; i < 4; i++) {
for (let j = 0; j < 3; j++) {
weight_1[i][j] = getRandomArbitrary(-1, 1);
}
}
console.table(weight_1)
When I run the code, I get the following output.
As can be seen in the picture, the random value changes only when i changes. Is this related to JS being asynchronous or because random numbers generated by Math.random has a relation to timestamp?
Array.prototype.valueOf is Object.prototype.valueOf, and simply returns the receiver value (this argument). It does not create a copy of the array - so you are mapping to an outer array that contains the same inner array at every index. Instead, use
function matrix(m, n, d) {
return Array.apply(null, new Array(m)).map(
function() {
return Array.apply(null, new Array(n)).map(
function() {
return d;
}
);
}
);
}
or the simpler and more conventionally formatted
function matrix(m, n, d) {
return Array.from({length: m}, () =>
Array.from({length: n}, () =>
d
)
);
}
Also you might want to make d a callback function and call it, so that you create your matrix directly by matrix(4, 3, () => getRandomArbitrary(-1, 1)) instead of initialising it with 0 and then looping it to change the values.
I recently ran into a problem where I need to figure out how to distribute items into buckets but I need to find all the ways to distribute them.
the input comes in as an array of integers that tell you the maximum each column can hold and there must be N amount of items in the array.
for example:
maxItems = 3
maximums = [4,2,1] # The order of maximums DOES matter meaning
# This means that the results of maximums = [2,4,1] are different from maximums = [1,2,4]
outputs = [[3,0,0],[2,1,0],[1,1,1],[2,0,1],[0,2,1]] # results are in no particular order
# notice how the sum of each result is equal to maxItems and each value in each of the rows are less than the value inside of maximums
I attempted to solve this problem in javascript but I am unable to figure out how to approach this problem. I wanted to start off by filling the first columns with as many numbers as possible and start moving to the right, but as the maximums array gets bigger, this method gets more inaccurate and I don't exactly know how to approach it at all.
If you have any more questions please feel free to ask if you dont understand the problem.
The code I started off with in javascript was
var all_combinations = function(N, maximums){
var empty = maximums.map(function(){return 0;}); // create empty array size of maximums filled with 0s
var s = 0;
for (var i = 0; i < empty.length && s < N;){
if (empty[i] >= maximums[i]){i++;continue;}
empty[i]++;
s++;
} // fill the left side with as many items as possible
// Then i would proceed to move one item at a time to the right side but some how i would need to do it for the whole array and this is where I get stuck.
};
I tried searching up this problem, but I never found out how to do it the way it was set up here. I tried finding similar problems but they were always unrelated to this. Maybe I am searching up the problem wrong. If someone can link a helpful resource that would be great.
If you have any questions please ask them. I will answer to the best of my abilities.
You could use a recursive approach with checking all parts of the constraints.
It works with an index and a temporary array for keeping the count of the items.
At start, the index is zero and the array is empty. With the call of fork, the first exit option is checked, which means the constraints are checked and if greater or equal count, then the recursion stops.
The second exit option is when the sum of the items reaches the wanted count, then the temporary array is pushed to the result set and the recursion ends.
In all other cases, fork is called again with either
same index i and an incremented value of the temporary array at the index, or
incremented index and the actual temporary array.
function getCombination(max, count) {
function fork(index, temp) {
var sum = temp.reduce((a, b) => a + b, 0);
if (max.some((a, i) => (temp[i] || 0) > a) || index === max.length || sum > count) {
return;
}
if (sum === count) {
result.push(temp);
return;
}
fork(index, max.map((a, i) => (temp[i] || 0) + (i === index)));
fork(index + 1, temp);
}
var result = [];
fork(0, []);
return result;
}
console.log(getCombination([4, 2, 1], 3));
.as-console-wrapper { max-height: 100% !important; top: 0; }
An iterative approach with a previous check if the sum plus value is smaller or equal than the wanted count.
function getCombination(max, count) {
function iter(index, sum, temp) {
var i;
if (count === sum) {
result.push(temp);
return;
}
for (i = max[index]; i >= 0; i--) {
if (sum + i <= count) {
iter(index + 1, sum + i, temp.concat(i));
}
}
}
var result = [];
iter(0, 0, []);
return result;
}
console.log(getCombination([4, 2, 1], 3));
.as-console-wrapper { max-height: 100% !important; top: 0; }
An easy to understand recursive solution with ECMA 6 generators:
for each i, place i items into the first slot if they fit, then distribute the others among the rest.
function* bucket_distributions(capacities,nItems){
if (capacities.length==1) {
if (capacities[0] >= nItems)
yield [nItems];
}
else if (capacities.length>1) {
for (var i=Math.min(capacities[0],nItems);i>=0;i--) {
for (subdist of
bucket_distributions(capacities.slice(1),nItems-i))
yield [i].concat(subdist);
}
}
}
console.log(Array.from(bucket_distributions([4,2,1],3)))
Here's a well-commented iterative solution with an interactive demo:
// reducer function for calculating sum of array
function sum(prev, next) {
return prev + next;
}
// returns the contextual constraints of a bucket
function bucketMinMax(maxItems, otherItems, bucketMax) {
return {
// minimum values in bucket to meet maxItems
min: Math.max(0, maxItems - otherItems),
// maximum values in bucket to meet maxItems
max: Math.min(maxItems, bucketMax),
};
}
// takes an incomplete combination and expands it with the next bucket
// starting from the left
function expandCombination(maxItems, maximums, combinations) {
// get next combo group to expand
var comboGroup = combinations.shift();
// get index of expansion bucket
var index = comboGroup.length;
// calculate maximum possible otherItems
var otherItems = maximums.slice(index + 1).reduce(sum, 0);
// removes already used spaces from maxItems in combination group being expanded
maxItems -= comboGroup.reduce(sum, 0);
// get constraints for expansion bucket
var {min, max} = bucketMinMax(maxItems, otherItems, maximums[index]);
for (var i = min; i <= max; i++) {
// add combo group expansions to output
combinations.push(comboGroup.concat([i]));
}
}
// main function
function allCombinations(maxItems, maximums) {
// will eventually contain all combinations
var output = [[]];
// loops through array of combinations, expanding each one iteratively
while (output.length > 0 && output[0].length < maximums.length) {
// takes incomplete combination group and expands it with possible values
// for next bucket starting from the left
expandCombination(maxItems, maximums, output);
}
return output;
}
document.addEventListener('change', () => {
var maxes = JSON.parse(maximums.value);
var items = JSON.parse(maxItems.value);
console.log(JSON.stringify(allCombinations(items, maxes)));
});
document.dispatchEvent(new Event('change'));
<label>maxItems
<input id="maxItems" value="3">
</label>
<label>maximums
<input id="maximums" value="[4,2,1]">
</label>
So I have a dice rolling function. I want to roll 2 dice 20 times, each time I roll, I want to add those numbers, and then I want to see how many times the sum appears, and put that number into an array.
function Dice() {
this.roll = function() {
var randomValue = Math.ceil(Math.random() * 6);
this.side = randomValue;
return this.side;
}
}
var dice1 = new Dice();
var dice2 = new Dice();
function getAmount() {
var finalArray = [];
function diceSum() {
var sum = dice1.roll() + dice2.roll();
return sum;
}
var trackSum = [];
for (var i = 1; i <= 20; i++) {
trackSum.push(diceSum());
}
var reduced = trackSum.reduce(function(acc, sum, i, arr) {
return acc.i += sum;
}, {});
return reduced;
}
so I get trackSum which has 20 numbers in an array which, each number is the sum of the 2 dice rolled. If sum = 2 and it appears 5 times, sum = 4, appears 2 times, sum = 3, appears 1 time, final array should look like
[5, 2, 1]
So far I tried a reduce method, filter, and forEach. I just can't figure out how to compare the numbers to see how many times it's appearing. Any help would be appreciated. Thanks!
Use an object whose keys are the sums, and values are the number of times the sum appears. Loop through trackSum and increment the value of the corresponding element.
var freq = {};
trackSum.forEach(function(sum) {
freq[sum] = freq[sum] ? freq[sum] + 1 : 1;
}
console.log(freq);
Apologies for answering my own question, but after some googling, I figured it out. So don't pay attention to the reduce method I have in my original post. This is what I did instead:
var countedSum = trackSum.reduce(function(emptyObj, sum, i, arr){
if (sum in emptyObj){
emptyObj[sum]++
} else {
emptyObj[sum] = 1
}
return emptyObj;
}, {});
This returns an object, with the sum value as the key, and the amount of times it happens as the value.
Then I learned a new method that grabs the values and puts it in an array.
Object.values(countedSum)
That solves it!
Thanks #Barmar for your help!
I have prepared 2 Javascript functions to find matching integer pairs that add up to a sum and returns a boolean.
The first function uses a binary search like that:
function find2PairsBySumLog(arr, sum) {
for (var i = 0; i < arr.length; i++) {
for (var x = i + 1; x < arr.length; x++) {
if (arr[i] + arr[x] == sum) {
return true;
}
}
}
return false;
}
For the second function I implemented my own singly Linked List, in where I add the complementary integer to the sum and search for the value in the Linked List. If value is found in the Linked List we know there is a match.
function find2PairsBySumLin(arr, sum) {
var complementList = new LinkedList();
for (var i = 0; i < arr.length; i++) {
if (complementList.find(arr[i])) {
return true;
} else {
complementList.add(sum - arr[i]);
}
}
return false;
}
When I run both functions I clearly see that the Linked List search executes ~75% faster
var arr = [9,2,4,1,3,2,2,8,1,1,6,1,2,8,7,8,2,9];
console.time('For loop search');
console.log(find2PairsBySumLog(arr, 18));
console.timeEnd(‘For loop search’);
console.time('Linked List search');
console.log(find2PairsBySumLin(arr, 18));
console.timeEnd('Linked List search');
true
For loop search: 4.590ms
true
Linked List search: 0.709ms
Here my question: Is the Linked List approach a real linear search? After all I loop through all the nodes, while my outer loop iterates through the initial array.
Here is my LinkedList search function:
LinkedList.prototype.find = function(data) {
var headNode = this.head;
if(headNode === null) {
return false;
}
while(headNode !== null) {
if(headNode.data === data) {
return true;
} else {
headNode = headNode.next;
}
}
return false;
}
UPDATE:
It was a good idea to go back and have another think of the problem based the comments so far.
Thanks to #nem035 comment on small datasets, I ran another test but this time with 100,000 integers between 1 and 8. I assigned 9 to the first and last position and searched for 18 to make sure the entire array will be searched.
I also included the relatively new ES6 Set function for comparison thanks to #Oriol.
Btw #Oriol and #Deepak you are right. The first function is not a binary search but rather a O(n*n) search, which has no logarithmic complexity.
It turns out my Linked List implementation was the slowest of all searches. I ran 10 iterations for each function individually. Here the result:
For loop search: 24.36 ms (avg)
Linked List search: 64328.98 ms (avg)
Set search: 35.63 ms (avg)
Here the same test for a dataset of 10,000,000 integers:
For loop search: 30.78 ms (avg)
Set search: 1557.98 ms (avg)
Summary:
So it seems the Linked List is really fast for smaller dataset up to ~1,000, while ES6 Set is great for larger datasets.
Nevertheless the For loop is the clear winner in all tests.
All 3 methods will scale linearly with the amount of data.
Please note: ES6 Set is not backward compatible with old browsers in case this operation has to be done client side.
Don't use this. Use a set.
function find2PairsBySum(arr, sum) {
var set = new Set();
for(var num of arr) {
if (set.has(num)) return true;
set.add(sum - num);
}
return false;
}
That's all. Both add and has are guaranteed to be sublinear (probably constant) in average.
You can optimize this substantially, by pre-sorting the array and then using a real binary search.
// Find an element in a sorted array.
function includesBinary(arr, elt) {
if (!arr.length) return false;
const middle = Math.floor(arr.length / 2);
switch (Math.sign(elt - arr[middle])) {
case -1: return includesBinary(arr.slice(0, middle - 1), elt);
case 0: return true;
case +1: return includesBinary(arr.slice(middle + 1), elt);
}
}
// Given an array, pre-sort and return a function to detect pairs adding up to a sum.
function makeFinder(arr) {
arr = arr.slice().sort((a, b) => a - b);
return function(sum) {
for (let i = 0; i < arr.length; i++) {
const remaining = sum - arr[i];
if (remaining < 0) return false;
if (includesBinary(arr, remaining)) return true;
}
return false;
};
}
// Test data: 100 random elements between 0 and 99.
const arr = Array.from(Array(100), _ => Math.floor(Math.random() * 100));
const finder = makeFinder(arr);
console.time('test');
for (let i = 0; i < 1000; i++) finder(100);
console.timeEnd('test');
According to this rough benchmark, one lookup into an array of 100 elements costs a few microseconds.
Rewriting includesBinary to avoid recursion would probably provide a further performance win.
first of all find2PairsBySumLog function is not a binary search, it's a kind of brute force method which parses all the elements of array and it's worst case time complexity should be O(n*n), and the second function is a linear search that' why you are getting the second method to run fastly, for the first function i.e. find2PairsBySumLog what you can do is initialize binary HashMap and check for every pair of integers in array kind of like you are doing in the second function probably like
bool isPairsPresent(int arr[], int arr_size, int sum)
{
int i, temp;
bool binMap[MAX] = {0};
for (i = 0; i < arr_size; i++)
{
temp = sum - arr[i];
if (temp >= 0 && binMap[temp] == 1)
return true;
binMap[arr[i]] = 1;
}
}
I'm trying to get whatever number is the most frequently occuring number in an array, so for an array containing 1,2,10,5,1 the result should be 1. The code I wrote returns me the frequency for each number, so 1 occurs twice, 2 occurs once, 10 occurs once etc. Any suggestions how I can fix my result?
function mode(arr) {
var uniqNum = {};
var numCounter = function(num, counter) {
if(!uniqNum.hasOwnProperty(num)) {
uniqNum[num] = 1;
} else {
uniqNum[num] ++;
}
};
arr.forEach(numCounter);
return uniqNum;
}
I've kept your code unchanged and added some extra statements. Here is the demo: http://codepen.io/PiotrBerebecki/pen/rrdxRo
function mode(arr) {
var uniqNum = {};
var numCounter = function(num, counter) {
if(!uniqNum.hasOwnProperty(num)) {
uniqNum[num] = 1;
} else {
uniqNum[num] ++;
}
};
arr.forEach(numCounter);
return Object.keys(uniqNum)
.sort((a,b) => uniqNum[b] - uniqNum[a]) // sort by frequency
.filter((val,ind,array) => uniqNum[array[0]] == uniqNum[val]) // leave only most frequent
.map(val => Number(val)); // convert text to number
}
console.log( JSON.stringify(mode([3,3,2,4,4])) ) // [3,4]
console.log( JSON.stringify(mode([2,4,3,3])) ) // [3]
I think it could be done only with a little modification to your forEach loop and the assistance of another auxiliary data structure:
function mode(arr) {
var freq = [], uniqNum = {}, i;
arr.forEach(function (num) {
uniqNum[num] = i = (uniqNum[num] || 0) + 1;
freq[i] = (freq[i] || []).concat(num);
});
return freq[freq.length - 1];
}
console.log(mode([1, 2, 3, 4, 5, 1, 2, 3, 4, 5, 6, 6, 7, 1, 6]));
With only one iteration over all the elements of the array we can gather enough information to print out the result:
uniqNum is the set you created to gather info about the element's frequency.
freq will be an array which last element will contain an array with the elements of higher frequency.
Fiddle. Hope it helps.
First we want to make an array where we count the number of occurrences of a certain value up to that point.
Then we use the reduce function to return an array of values read from the original array for the indexes whose values have the current max appearances. We redefine max and empty the final output array of modes (if new max is established) as we go along. We want this to be a collection in case there is a tie for maximum appearances.
Additional advantage of the below is that it doesn't require sort which is more expensive o(nlog n) and keeps the time complexity down to just linear. I also wanted to keep the functions used down to only two (map and reduce) as it is all that is need in this case.
edit: fixed a major bug uniqNum[e] += 1 instead of uniqNum[e] + 1 which went unnoticed as my initial case array was still returning expected result. Also made the syntax more concise in favor of more comments.
var arr = [1,2,10,5,1,5,2,2,5,3,3];
//global max to keep track of which value has most appearances.
var max = -1;
var uniqNum = {};
var modeArray = arr.map(function(e) {
//create array that counts appearances of the value up to that point starting from beginning of the input arr array.
if(!uniqNum.hasOwnProperty(e)) {
uniqNum[e] = 1;
return 1;
} else {
return uniqNum[e] += 1;
}
//reduce the above appearance count array into an array that only contains values of the modes
}).reduce(function (modes, e1, i) {
//if max gets beaten then redefine the mode array to only include the new max appearance value.
if(e1 > max){
//redefining max
max = e1;
//returning only the new max element
return [arr[i]];
//if its a tie we still want to include the current value but we don't want to empty the array.
}else if(e1 == max){
//append onto the modes array the co-max value
return[...modes, arr[i]];
}
return modes;
},[]);
alert(modeArray);
Here is a test you can run of my solution against #acontell. In my browser (Chrome with V8) my solution was around three-four times faster for arrays with large number of repeating values and even bigger advantage with distributions with lower number of repeating values. #acontell 's is a cleaner looking solution for sure, but definitely not faster in execution.
var arr = [];
for(var i=0; i < 100000; i++){
arr.push(Math.floor(Math.random() * (100 - 1)) + 1);
}
console.time("test");
test();
function test(){
var max = -1;
var uniqNum = {};
var modeArray = arr.map(function(e) {
//create array that counts appearances of the value up to that point starting from beginning of the input arr array.
if(!uniqNum.hasOwnProperty(e)) {
uniqNum[e] = 1;
return 1;
} else {
return uniqNum[e] += 1;
}
//reduce the above appearance count array into an array that only contains values of the modes
}).reduce(function (modes, e1, i) {
//if max gets beaten then redefine the mode array to only include the new max appearance value.
if(e1 > max){
//redefining max
max = e1;
//returning only the new max element
return [arr[i]];
//if its a tie we still want to include the current value but we don't want to empty the array.
}else if(e1 == max){
//append onto the modes array the co-max value
modes.push(arr[i])
return modes;
}
return modes;
},[]);
}
console.timeEnd("test");
console.time("test1");
test1();
function test1 () {
var freq = [],
uniqNum = {},
i;
arr.forEach(function(num) {
uniqNum[num] = i = (uniqNum[num] || 0) + 1;
freq[i] = (freq[i] || []).concat(num);
});
return freq[freq.length - 1];
}
console.timeEnd("test1");
I've tried as an exercise to solve this with native js functions.
var arr = [1,2,10,5,1];
// groupBy number
var x = arr.reduce(
function(ac, cur){
ac[cur]?(ac[cur] = ac[cur] + 1):ac[cur] = 1;
return ac;
}, {}
);
// sort in order of frequencies
var res = Object.keys(x).sort(
function(a,b){ return x[a] < x[b]}
);
res[0] has the most frequent element