Javascript - return array of values that totals next number up - javascript

I am trying to work out the best way to achieve the following:
A score might require a total of 25 'items' AS A MINIMUM
currently that person might have 15.8 'items'
I have a number of items required to reach that score (9.2)
So to get that score the minimum a person must have is 10 'items' in x weeks (to be 25.8 and over the 25 threshold).
Assuming they have 4 weeks to do it that gives 2.5 needed per week.
What I am struggling with is how to output an array of 'whole items' that will make 10.
e.g.
2
3
2
3
I want the items to be as evenly distributed as possible.
so
1
2
3
4
would be useless
I am just trying to work out the best way to do this.
I was thinking of:
finding nearest whole number ROUNDED UP (3 in this example)
Then outputting that number
Then on the next pass gathering the 'remainder' (-0.5) and then rounding the number.
But it doesn't quite work for all cases.
Can anyone help me get my head around it without writing hundreds of lines of code.
As a further example say 17 were needed in 5 weeks that would be
4
3
3
4
3
Thanks in advance.

You could do it some way like this:
function myFunction(total, weeks) {
var n = 0;
var temp = 0;
var arr = [];
while (n < total) {
temp = n;
n += total / weeks;
arr.push(Math.floor(n) - Math.floor(temp));
}
return arr;
}
myFunction(10, 4); //[2, 3, 2, 3]
myFunction(17, 5); //[3, 3, 4, 3, 4]
In this code, total / weeks will be the average number you'll want to add to n to get from 0 to total in exactly weeks iterations.
Now the difference between the original value of n (which is stored in temp) and the new value of n is pushed to the array. That will give you the rounded numbers you'll need to add up to the entered total.

Related

Find The Smallest - Codewars Challenge - Javascript

Trying to solve this Codewars challenge.
You have a positive number n consisting of digits. You can do at most one operation: Choosing the index of a digit in the number, remove this digit at that index and insert it back to another or at the same place in the number in order to find the smallest number you can get.
Task: Return an array or a tuple or a string depending on the language (see "Sample Tests") with:
1) the smallest number you got
2) the index i of the digit d you took, i as small as possible
3) the index j (as small as possible) where you insert this digit d to have the smallest number.
Example:
smallest(261235) --> [126235, 2, 0] or (126235, 2, 0) or "126235, 2, 0"
Other examples:
209917, [29917, 0, 1]
285365, [238565, 3, 1]
269045, [26945, 3, 0]
296837, [239687, 4, 1]
So, in order to get the smallest number possible, we will want to remove the smallest digit from the number and place it at the front of the number, correct?
function smallest (n) {
//turn n into an array
let array = String(n).split("").map(Number);
let smallest = Math.min(...array);
//find index of smallest in original array
let index = array.indexOf(smallest);
//remove smallest from original array, move it to front
array.splice(index, 1);
array.unshift(smallest);
let newNumber = Number(array.join(""));
//return array of new number, index of where the smallest was,
//and index of where the smallest is now
return ([newNumber, index, 0]);
}
console.log(smallest(239687));
My answer is returning the correct number, but, about half the time, it is not returning the correct index i and index j.
EDIT: Latest attempt:
function smallest (n) {
let array = Array.from(String(n)).map(Number);
let original = Array.from(String(n)).map(Number);
let sorted = Array.from(String(n)).map(Number).sort((a, b) => a - b);
let swapValueOne = [];
let swapValueTwo = [];
for (let i = 0; i < array.length; i++) {
if (array[i] !== sorted[i]) {
swapValueOne.push(sorted[i]);
swapValueTwo.push(original[i]);
break;
}
}
swapValueOne = Number(swapValueOne);
swapValueTwo = Number(swapValueTwo);
let indexOne = original.indexOf(swapValueOne);
let indexTwo = original.indexOf(swapValueTwo);
//remove swapValue
array.splice(indexOne, 1);
//insert swapValue
array.splice(indexTwo, 0, swapValueOne);
return ([Number(array.join("")), indexOne, array.indexOf(swapValueOne)]);
}
console.log(smallest(296837));
^ Sometimes it gives the correct number with the correct swap indices, and sometimes both the number and the swap indices are wrong.
Putting the smallest element in the front (let's call it a "greedy" solution) is non-optimal. Consider the case where n = 296837, as in your last test case. Your code returns [296837, 0, 0] because it finds that 2 is the smallest digit and it moves it to the front (does nothing, essentially). As your example illustrates, there's a better approach: [239687, 4, 1], that is, move 3 to the first index in the array.
You'll need to reformulate your strategy to be non-greedy to find a global optimum.
If you're still stuck, you can try the following:
Numbers can't contain that many digits--why not try every possible swap?
Here's a small idea that might help.
If you have a number like:
239687
The smallest number you can make with this is the sorted digits:
236789
In the original number, the 2 and the 3 are already in the correct position. If you start from the left of the number and the sorted number, the first difference you find is the number that needs to be swapped. It needs to be swapped with the corresponding number in the sorted list:
orig 2 3 9 6 8 7 -- 6 needs to go before 9
| | x
sorted 2 3 6 7 8 9
Above the next sorted digit is 6, but the original has 9. You need to insert 6 before 9.
For an algorithm you can sort your digits and find the index of the first difference (starting from the left). This is one of your return values (2 in the example). Now find the index of sorted[2] (ie. 6) in the original (index 3). Insert the value in you original array and you're done.
The approach of finding the first not sorted element doesnt solve correctly all the cases for example if the number is 300200, the first not sorted number is the 3 and if you put a 0 in that place, depending what 0 you move you got:
(0)30020
(0)30020
(0)30200
(0)30200
All of the answers are wrong because what you have to do is to put the 3 at the end of the number to get
(000)2003

Can I represent large integers in Node 6 for only exponentiation without a dependency?

I am working on a kata that asks for the last digit of a[0] ^ (a[1] ^ (a[2] ^ ... (a[n-1] ^ a[n]))). When computing the answer, eventually Math.pow exceeds Number.MAX_SAFE_INTEGER, causing modexp below to return erroneous results.
#user2357112 says that JS needs a library for arbitrary-precision integers, which is all well and good, but nothing in the kata indicates that such a library is available in the remote environment, or even that I need one.
Since the kata and SO point in different directions on this matter, I want to learn if I can feasibly represent big integers ONLY for the purposes of solving this kata without writing an entire library.
My in-progress code is below, and it passes many tests before printing incorrect results. Some code was omitted to avoid spoilers.
TL;DR: If I cannot use a library, what can I do to feasibly represent large integers for the use case indicated by Math.pow()?
function modexp(b, e) {
let c = 1
while(e) {
if (e & 1)
c = c * b % 10
e >>= 1
b = b * b % 10
}
return c;
}
function lastDigit(as) {
if (!as || !as.length) return 1;
let e = as.slice(1).reverse().reduce((p,c) => Math.pow(c,p));
return modexp(as[0], Number(e));
}
This is obviously an X-Y problem. You don't need large integers.
You need to go back to elementary school math.
What's multiplication? Well let's take one example:
WARNING: SPOILERS! Don't read the following if you want to figure it out yourself!
1 2
x 2 3
------
3 6 last digit 6
2 4
------
2 7 6 notice how last digit is only involved
in ONE multiplication operation?
Hmm.. there seems to be a pattern. Let's see if that pattern holds. Let's multiply 12 x 23 x 23 by only doing the last digit:
1 2
x 2 3
------
6 calculate ONLY last digit
x 2 3
------
8 answer is: last digit is 8
Let's check our answer:
1 2
x 2 3
------
3 6
2 4
------
2 7 6
x 2 3
------
8 2 8
5 5 2
-------
6 3 4 8 last digit is INDEED 8
So it seems that you can find the last digit by only calculating the last digit. Let's try to implement a powLastDigit() function.
WARNING: SPOILERS! DON'T READ THE CODE IF YOU WANT TO WRITE IT YOURSELF!
function powLastDigit (number,power) {
var x = number;
for (var y=1; y<power; y++) {
x = ((x%10)*(number%10))%10; // we only care about last digit!
}
return x;
}
Let's check if we are right:
> powLastDigit(3,7)
7
> Math.pow(3,7)
2187
> powLastDigit(5,8)
5
> Math.pow(5,8)
390625
> powLastDigit(7,12)
1
> Math.pow(7,12)
13841287201
OK. Looks like it's working. Now you can use this function to solve your problem. It has no issues with very large exponents because it doesn't deal with large numbers:
> powLastDigit(2323,123456789)
3
Optimization
The above code is slow because it uses a loop. It's possible to speed it up by using Math.pow() instead. I'll leave that as a homework problem.
I use bit array to represent a positive integer;
[0,0,1,1] // bit array of 12 (MSB=rightmost)
This structure is used to manipulate the overall exponent, E
a[1] ^ (a[2] .. (a[n-1] ^ a[n])) // E
(!)There is a relation between LSD(a[0]) and the overall exponent E as below
//LSD(a[0]) LSD(LSD(a[0]) ^ E) for
// [E/4R0, E/4R1, E/4R2, E/4R3]
//--------- ----------------------------
// 0 [0, 0, 0, 0]
// 1 [1, 1, 1, 1]
// 2 [6, 2, 4, 8]
// 3 [1, 3, 9, 7]
// 4 [6, 4, 6, 4]
// 5 [5, 5, 5, 5]
// 6 [6, 6, 6, 6]
// 7 [1, 7, 9, 3]
// 8 [6, 8, 4, 2]
// 9 [1, 9, 1, 9]
For example, find least significant digit of (2 ^ (2 ^ 3)),
// LSD(a[0]) is 2
// E is 8
// implies E mod 4 is 0
// LSD(LSD(a[0]) ^ E)
// for E/4R0 is 6 (ans)
To determine E mod 4,
E[0] + E[1] * 2 // the two LSBs
To summarize, I create a data structure, bit array, to store large integers,
mainly for the intermediate value of exponent-part. The bit array is dynamic length obtaining max. 9007199254740991 bits, if all bits are set, the value in decimal is 2 ^ (9007199254740991 + 1) - 1. This bit array will never be converted back to decimal(safe). The only interesting information of overall exponent, E, is its two least significant bits, they are the remainder of E/4
which can be applied to the above relation(!).
Obviously, Math.pow will not work for bit array, so I handcraft a simple exp() for it. This is trivial since the fact that
//exponentiation == lots of multiplications == lots of additions
//it is not difficult to implement addition on bit array
This is the fiddle demonstrating above idea ONLY. It is intended to be slow if the E is really large. FYI
LSD.find([3,4,5,6]) // my Nightly hanged ~3s to find lsd
You may optimize the Bits.exp by means of childprocesses, web workers, debounce function, simd etc. Good luck.
You don't really need a bigint library to solve this kata.
You are only interested in the last digit of the result, and fortunately there is a property of powers that helps us with this. We effectively want to compute a power in modulus 10. Yes, modular exponentiation does help us a bit here, but the problem is that the exponent is very large as well - too large to compute, and too large to run a loop with that many iterations. But we don't need to, all we are interested in is the modulus of the result.
And there is a pattern! Let's take 4x as an example:
x 4^x (4^x)%10
--------------------------
0 4^0 = 1 1
1 4^1 = 4 4
2 4^2 = 16 6
3 4^3 = 64 4
4 4^4 = 256 6
5 4^5 = 1024 4
… …
20 4^20 = ??? 6 sic!
21 4^21 = ??? 4
… …
You will be able to find these patterns for all numbers in all modular bases. They all share the same characteristic: there's a threshold below which the remainder is irregular, and then they form a repeating sequence. To get a number in this sequence, we only need to perform a modulo operation on the exponent!
For the example above ((4^x)%10), we use a lookup table 0 → 6, 1 → 4 and compute x % 2; the threshold is 1. In JavaScript code, it might look like this:
x < 1 ? 1 : [6, 4][x % 2];
Of course, x is a very large number formed by the repeated exponentiation of the rest of the input, but we do not need to compute it as whole - we only want to know
whether it is smaller than a relatively small number (trivial)
what the remainder after division by q is - just a recursive call to the function we're implementing!

Check lines A and count it until it changes to lines B javascript

I am sorry in advance if my title is somehow misleading and I am really sorry for my English if you wouldn't understand me, it's just not my native language!
I will try to explain as better as I can about what I try to achieve. I try to do this for past two entire days and I really need your help!
Let's say I have array with the following numbers:
2 4 6 8 10 1 3 5 2 4
I am trying to count how many even and odd numbers are here in a row, and when even/odd changes - count it again. So my answer from the array above should be:
5 (5 even numbers in a row) 3 (3 odd lines in a row) (2 even lines in a row)
Also when the counting isn't stopped it should post "<br>" instead of counted evens/odds, so it could show me results one time near to each line.
Check this example image:
I have this script which is counting, but it has a few issues: when number is even, it shows counting twice. Next, I can't figure it out how to add <br> to these lines where counting and add result only at the last line of counting. Also my counting result should be at the top, so the script should count from the end as I guess, and when I try i-- it starts the infinite loop...
var digits = ["2, 4, 6, 8, 10, 1, 3, 5, 2, 4"]
var evenCount=1, oddCount=1;
for(var i =0; i < digits.length; i++){
if(digits[i] % 2 ==0){
var oddCount=1;
$("#res").append(evenCount + " (l) <br>");
evenCount++;
}
else
var evenCount=1;
$("#res").append(oddCount + " (n) <br>");
oddCount++;
}
Check my fiddle to see it in action:
https://jsfiddle.net/xk861vf9/8/
First, I think your code show counting twice because you misses two '{' after "for loop" and "else". After I fix the code format, I don't see it counting twice anymore.
$(document).ready(function() {
$("#sub").bind("click", function() {
$("#res").html("");
var digits = $('#content').find("span").map(function() {
return $(this).text();
});
var evenCount = 1;
var oddCount = 1;
for(var i =0; i < digits.length; i++) {
if (digits[i] % 2 ==0) {
oddCount = 1;
$("#res").append(evenCount + " (l) <br>");
evenCount++;
} else {
evenCount=1;
$("#res").append(oddCount + " (n) <br>");
oddCount++;
}
}
});
});
Second, they are many ways to implement that. Take a look at this jsfiddle code as an example.
https://jsfiddle.net/xk861vf9/11/
The concept is to print the counted number after even/odd number changes. Then use for loop to print <br> x times (counted number - 1) so if counted number is 4, there will be 3 <br> tags followed.We also have to check if current number is the last number in array and print the counted number or else the last counted number will be skipped.
Hope this help! :)
Ps. Sorry for my bad English, not my native language too.

Decomposing a value into results of powers of two

Is it possible to get the integers that, being results of powers of two, forms a value?
Example:
129 resolves [1, 128]
77 resolves [1, 4, 8, 64]
I already thought about using Math.log and doing also a foreach with a bitwise comparator. Is any other more beautiful solution?
The easiest way is to use a single bit value, starting with 1 and shift that bit 'left' until its value is greater than the value to check, comparing each bit step bitwise with the value. The bits that are set can be stored in an array.
function GetBits(value) {
var b = 1;
var res = [];
while (b <= value) {
if (b & value) res.push(b);
b <<= 1;
}
return res;
}
console.log(GetBits(129));
console.log(GetBits(77));
console.log(GetBits(255));
Since shifting the bit can be seen as a power of 2, you can push the current bit value directly into the result array.
Example
You can adapt solutions from other languages to javascript. In this SO question you'll find some ways of solving the problem using Java (you can choose the one you find more elegant).
decomposing a value into powers of two
I adapted one of those answers to javascript and come up with this code:
var powers = [], power = 0, n = 129;// Gives [1,128] as output.
while (n != 0) {
if ((n & 1) != 0) {
powers.push(1 << power);
}
++power;
n >>>= 1;
}
console.log(powers);
Fiddle
Find the largest power of two contained in the number.
Subtract from the original number and Add it to list.
Decrement the exponent and check if new 2's power is less than the number.
If less then subtract it from the original number and add it to list.
Otherwise go to step 3.
Exit when your number comes to 0.
I am thinking of creating a list of all power of 2 numbers <= your number, then use an addition- subtraction algorithm to find out the group of correct numbers.
For example number 77:
the group of factors is { 1,2,4,8,16,32,64} [ 64 is the greatest power of 2 less than or equal 77]
An algorithm that continuously subtract the greatest number less than or equal to your number from the group you just created, until you get zero.
77-64 = 13 ==> [64]
13-8 = 7 ==> [8]
7-4 = 3 ==> [4]
3-2 = 1 ==> [2]
1-1 = 0 ==> [1]
Hope you understand my algorithm, pardo my bad english.
function getBits(val, factor) {
factor = factor || 1;
if(val) {
return (val % 2 ? [factor] : []).concat(getBits(val>>1, factor*2))
}
return [];
}
alert(getBits(77));

Bucketing numbers in an array

I have a list of numbers e.g 1-to 60, but not necessarily in increments of 1. E.g 1-40 in increments of 1, and 40-60 in increments of two.
I have another set of defined numbers (buckets) –e.g 2, 3, 5 , 10, 30, 50
I need to produce a two dimensional array with percentages of where each number from above (1 to 60) fits into which bucket.
to make this simpler: let’s say we have numbers 1 to 10, and buckets, 2, 3, 5, 10
I want my two dimensional array to look like this:
I can do this with a bunch of conditionals, but I think there’s a solution out there which I have not thought of and would be great if someone could shed some light!
I need to do this in JavaScript, but any language would help me to try and understand any solution more optimal than lots of if’s deciding where each number fits and then doing (6-5/10-5)=0.2 for each cell.
I’m trying to avoid hardcoding buckets, 2, 3, 5, 10 so that any set of buckets or numbers can do the job.
EDIT:
First of all, I'm sorry for the incomplete description - I was on my phone at the time and couldn't post on stackoverflow via a computer.
Both 1-10 and 2,3,5,10 represent years. Effectively, I'm trying to bucket each year from 1 to 10.
Year 1 goes 100% into Bucket 2 - I guess there isn't a specific
formula for this cell
Year 2 goes 100% into Bucket 2 - No specific formula either
Year 3 goes 100% into Bucket 3 - 3==3
Year 4 is split half between Bucket 3, and half between Bucket 5. The formula for this is: (Year 4 - Bucket 3)/(Bucket 5 - Bucket 3) = 0.5
Year 5 goes 100% into Bucket 5.
Year 6, goes 80% into Bucket 5, and 20% into Bucket 10. The formula for this is: 1-(6-5)/(10-5)=0.8 and for its neighbouring cell (6-5)/(10-5)
...and so on...
I hope this makes it clearer.
You could do something like this. It puts it in exactly the format you asked for in the post:
function bucketize(numberList, buckets) {
// buckets must contain values sorted from smallest to largest
var bucketized = [];
var i, j, lowBucket, difference, bucketSpan, ratio;
for (i=0; i<numberList.length; i++) {
bucketized[i]=new Array(buckets.length + 1);
bucketized[i][0]=numberList[i];
lowBucketIndex=null;
for (j=0; j<buckets.length; j++) {
if (lowBucketIndex === null && numberList[i] < buckets[j]) {
lowBucketIndex=j-1;
if (lowBucketIndex < 0) {
// this bucket gets it all
bucketized[i][j+1]=1;
} else {
//divide this value between buckets
difference = numberList[i] - buckets[lowBucketIndex];
bucketSpan = buckets[j] - buckets[lowBucketIndex];
ratio=difference/bucketSpan;
bucketized[i][lowBucketIndex+1] = 1-ratio;
bucketized[i][j+1] = ratio;
}
} else {
bucketized[i][j+1]=0;
}
}
if (lowBucketIndex === null) {
bucketized[i][buckets.length] = 1;
}
}
return bucketized;
}
var buckets = [2,3,5,10];
var numberList=[1,2,3,4,5,6,7,8,9,10];
var bucketized = bucketize(numberList, buckets);
var i;
for (i=0; i<bucketized.length; i++) {
console.log(bucketized[i].join(','));
}
Here's a fiddle.

Categories