percent chance logic issue/refactoring (javascript) - javascript

I have an array of numbers, each one of these number represents weight. the numbers in the array is between 0 and 1, and the total of these numbers adds up to 1. So if say array[1] is 0.6 then that represents I want it to show about 60% of the time. The array itself is not known to me so I don't know these numbers, they are user input for example.
I have a solution that will work but i don't know if it is the most efficient way to do this. My solution just seems very inefficient. Here it is
generate random number
copy this user input array into a new array and sort it from smallest to largest
compare the random number to numbers in this new array, so it would compare from the smallest in the array to the largest, when random number is smaller than the array number then I will store the array number into a variable say x and exit the loop
finally, i will compare x with the original array to figure out what the index of x is in the original array
this seems like a lot of work to do, is there a simpler solution? my head does not spin that fast
EDIT - the original array is not sorted in any way
EDIT 2 - Basically I am having trouble comparing this random number to the unsorted array. I need the unsorted to stay the same which is why I created that new array in my logic

If you have an array whose elements sum to 1, you can use the following algorithm:
Pick a uniformly distributed (pseuo)random number, r, between 0 and the sum of the weights.
For each weight,
If r is less than the weight, pick it and exit.
Otherwise subtract the weight from r, so it is now between 0 and the sum of the remaining weights.
Since r is always between 0 and the sum of the remaining weights, there is always a chance proportional to each weight that r is less than it when the loop reaches that weight.
In JavaScript:
var weights = [0.5, 0.15, 0.3, 0.05];
var index = weights.length - 1; // Last by default to avoid rounding error.
var r = Math.random();
for (var i = 0; i < a.length - 1; ++i) {
if (weights[i] > r) { index = i; break; }
// The rest of the array sums to
// 1 - sum(weights[0]..weights[i])
// so rescale r appropriately.
r -= weights[i];
}
will give you the desired distribution.
The trick is the r -= which makes sure that r is always between 0 and the sum of the unprocessed array elements.
You can test it at http://jsfiddle.net/KdKdb/

Related

Splitting an array into columns, where the total child elements is roughly equal

I'm trying to achieve some tricky functionality within Javascript for creating a directory page. The directory page works by having items assigned to a letter (which is the first letter of the item).
For example:
{
A: [Alfie, Amelia, Ava, Alex, Aaron],
B: [Ben, Bella, Blake, Bailey, Bradley]
...
}
Essentially, the output should be 4 sub-arrays. These sub-arrays should be an array of letters. However, the functionality should decide how many letters are in each array by the number of items that are assigned to that letter.
So, the first array could contain only 3 letters, as each letter has 5 items assigned (totalling). The second array could contain 7 letters, as the total of sum of their children is roughly 15.
For example:
[
[A (5), B (5), C (5)],
[E (4), F (1), G (1), H (2), I (3), J (2), K (1)]
...
]
It's worth nothing that it isn't important for each of the 4 arrays to contain EXACTLY the same amount of items because it's likely for this not to be possible.
I'm not sure how I'd begin to achieve this functionality. Any points in the right direction would be much appreciated
Here is a simple approach for the question asked.
First, it is easy given maximum height of any column to figure out how many columns you will need. Just attempt it.
Next, the maximum height must be in the range from the largest number of items assigned to a letter, to the sum of all items assigned to all letters.
And now we can do a binary search to find the smallest allowed height that has at most 4 columns. The key loop should look something like:
while (lower < upper) {
let mid = Math.ceil((lower + upper)/2);
if (divideIntoColumns(items, mid).length <= 4) {
lower = mid;
}
else {
upper = mid - 1;
}
}
As #trincot pointed out, titles also take space. The easiest way to take that into account is do make you divideIntoColumns function be the estimated height of the column in a convenient unit (eg pixels). Even if that multiplies the size of your numbers by a factor of 20, that's just 4-5 extra rounds of binary search, which will be fine.

Fill numbers from 1 to n,fast algorithm

I need algorithm what can fill string/array/etc by numbers from 1 to n; 1 <= 1 <= 10^8.
Time limit ≈ 2 seconds.
n = 100000000;
arr = [];
for (let i = 1;i <= n;i++){
arr.push(i)
}
console.log(arr)
If try like this it takes 33.785 seconds that too much
You make multiple reallocation of memory for string - this is rather long procedure.
If possible - preset list/array capacity, then fill it with values, rather than increment length one-by-one. In Python you can use list comprehension - perhaps JS has something alike.
For strings use a kind of StringBuilder if available.

How to randomly pick a number of combinations from all the combinations efficiently

For example I have two array (first array contains first names and second array last names). I want to generate n number of unique, non-repeating combinations from this two arrays with such ordering >>> first_name + ' ' + last_name.
I don't wish to generate every possible combination beforehand, because it's too much memory-consuming.
So what I think that algorithm should do, is to iterate until combinations are not generated, during iteration, it should give some random indexes for both arrays and if those indexes are already used together try to pick another random numbers until unique indexes are not generated.
But this approach might trigger deep recursion during runtime, since as many outputs are already given, a chance that new random indexes will be matched with existing ones is going higher at each step.
So what is your suggestion guys, how can I select random, unique n items from non-existing/virtual 2 array element combinations with very optimized way
If you have F unique first names and L unique last names, then overall number of combinations is N = F * L
So you can generate needed number of non-repeating random integer values in range 0..N-1 (for example, with Fisher-Yates sampling), sort them, and get corresponding name combinations:
for i = 0..M-1
Generate K[i] = Random(N)
Sort K[]
for i = 0..M-1
FirstNameIndex = K[i] / L //integer division
LastNameIndex = K[i] % L //integer modulo
Combination[i] = First[FirstNameIndex] + Last[LastNameIndex]

How to efficiently randomize a relatively small array of all the same floats preserving the sum total?

How to efficiently randomize a relatively small array of all the same floats preserving the sum total?
For example:
I have an array of equal floats:
[ 0.1, 0.1, 0.1, 0.1, 0.1 ] // sum === 0.5
I want to randomize it like this:
[ 0.1, 0.2, 0.0, 0.15, 0.05 ] // sum === 0.5
The initial array is always of equal values but it could be in various ranges:
[ 3.56, 3.56, 3.56, 3.56, 3.56 ]
I dont know the actual size these initial arrays will end up being but I'm guessing they will be between 50 to 100 items in length.
(FYI: These are note durations, bonus points if the algorithm is musical)
1) Calculate n random floats between 0 and 1
2) Calculate the sum of these n numbers.
3) You have to divide the sum with itself and multiply it with the sum you want to get (in the following the resultsum). So if you divide every of the n numbers generated in 1) with the sum calculated in 2) and multiply the result with the resultsum, then you get the random numbers you want in your result.
Not musical but:
1) Calculate the sum of all values in the array.
2) Generate N-1 points between 0 and sum, where N is the number of entries in the array.
3) Order these N-1 points from smallest to greatest, then augment the array with 0 on the left and sum on the right. Basically, imagine that you've taken a bar of sum length and chopped it at N-1 points.
4) For each element in the now N+1 points (excluding the first), calculate its difference between it and the previous point. The sum of these differences is still sum - you can prove this to yourself by imagining the chopped up bar's pieces being the differences. If you cut a bar of length 1 at 0.2 and 0.7, then you augment to get 0,0.2,0.7,1.0 and the differences are 0.2, 0.5, 0.3 which sum to 1.
5) Shuffle the output of 4) randomly (Fisher-Yates shuffle if you need to implement it)
If you wanted to make it musical, you might want to 'discretify' step 2, by which I mean something like:
a) divide the first element of array by 2 (call this D) (e.g. 0.1/2 = 0.05)
b) divide sum by D (call this Sd) (e.g. 0.5/0.05 = 10)
c) create your random numbers from 0 to Sd as integers, then multiply them by D
d) now continue from 3 in the original algorithm
This will give you only semiquavers. If you use 4 instead of 2 you get semidemiquavers, and so on

Chunk a string every odd and even position

I know nothing about javascript.
Assuming the string "3005600008000", I need to find a way to multiply all the digits in the odd numbered positions by 2 and the digits in the even numbered positions by 1.
This pseudo code I wrote outputs (I think) TRUE for the odd numbers (i.e. "0"),
var camid;
var LN= camid.length;
var mychar = camid.charAt(LN%2);
var arr = new Array(camid);
for(var i=0; i<arr.length; i++) {
var value = arr[i]%2;
Alert(i =" "+value);
}
I am not sure this is right: I don't believe it's chunking/splitting the string at odd (And later even) positions.
How do I that? Can you please provide some hints?
/=================================================/
My goal is to implement in a web page a validation routine for a smartcard id number.
The logic I am trying to implement is as follows:
· 1) Starting from the left, multiply all the digits in the odd numbered positions by 2 and the digits in the even numbered positions by 1.
· 2) If the result of a multiplication of a single digit by 2 results in a two-digit number (say "7 x 2 = 14"), add the digits of the result together to produce a new single-digit result ("1+4=5").
· 3) Add all single-digit results together.
· 4) The check digit is the amount you must add to this result in order to reach the next highest multiple of ten. For instance, if the sum in step #3 is 22, to reach the next highest multiple of 10 (which is 30) you must add 8 to 22. Thus the check digit is 8.
That is the whole idea. Google searches on smartcard id validation returned nothing and I am beginning to think this is overkill to do this in Javascript...
Any input welcome.
var theArray = camid.split(''); // create an array entry for each digit in camid
var size = theArray.length, i, eachValue;
for(i = 0; i < size; i++) { // iterate over each digit
eachValue = parseInt(theArray[i], 10); // test each string digit for an integer
if(!isNaN(eachValue)) {
alert((eachValue % 2) ? eachValue * 2 : eachValue); // if mod outputs 1 / true (due to odd number) multiply the value by 2. If mod outputs 0 / false output value
}
}
I discovered that what I am trying to do is called a Luhn validation.
I found an algorithm right here.
http://sites.google.com/site/abapexamples/javascript/luhn-validation
Thanks for taking the time to help me out. Much appreciated.
It looks like you might be building to a Luhn validation. If so, notice that you need to count odd/even from the RIGHT not the left of the string.

Categories

Resources