How to calculate balanced tiers on ranked values - javascript

I have an array of ranked values that I would like to group by x number of tiers for a given report. In this example, I have a list of 20 items and would like to calculate a total of 5 tiers so that the tiers are as evenly spread out as possible. In other cases, there might be a total of 31 items and 4 tiers. How could I write a function to handle this? Below are sample data and what the calculated tier for each item should be.
The reason why I would like to do this is to examine a difference in trends based upon the volume of included metrics. The table above is an example only because the data I am actually working with is not something I can share.

UPDATE
After some testing, this is the function I came up with:
function getTier(num_tiers, arr_length, rank){
var c = Math.floor(arr_length / num_tiers, 1),
m = (rank - 1) % c;
var result = Math.floor(((rank / c) - (m / c)) + 1, 0);
return (result > num_tiers) ? num_tiers : result;
}

Related

Recursive Functions Runtime 2^n - 1

I have the following function fn(n).
function fn(n) {
if (n < 0) return 0;
if (n < 2) return n;
return fn(n - 1) + fn(n - 2);
}
I understand how this code works, but don't how to calculate time complexity for it.
Let’s do some examples:
For n = 3, you have 5 function calls. First fn(3), which in turn calls fn(2) and fn(1) and so on.
For n = 4, you have 9 function calls. First fn(4), which in turn calls fn(3) and fn(2) and so on.
Graphical representation of the 2 examples:
The leftmost nodes go down in descending order: fn(4), fn(3), fn(2), fn(1), which means that the height of the tree (or the number of levels) on the tree will be n.
The time complexity of this code is 2^n - 1. Although, if we count all calls will be just 9 calls for n = 4.
And the question is how we get 2^n - 1? I don't understand
One of the ways of calculating recursive algorithm's time complexity is using the Recursion Tree Method. For this particular case, we can write T(n)=T(n-1)+T(n-2)+2*O(1), where O(1) means constant time, since we have two comparison checks of n values using if. The recursion tree would look something like this:
1 n
2 (n-1) (n-2)
4 (n-2) (n-3) (n-3) (n-4)
8 (n-3)(n-4) (n-4)(n-5) (n-4)(n-5) (n-5)(n-6)
...
2^i for i-th level
Total work done will be the sum of all of the work done in each level, so we can write T(n)=1 + 2 + 4 + 8 + 16 + 32 + ... = 2^0 + 2^1 + 2^2 + 2^3 + 2^4 + ... + 2^i. This is a geometric series which means that the T(n) is equal to (1-2^n)/(1-2) = (1-2^n)/(-1) = 2^n - 1. Because of that the time complexity of the function fn(n) is O(2^n).
You could also approach this using Back Substitution method. We know the following:
T(0)=1
T(1)=1
T(2)=1
T(n)=T(n-1)+T(n-2)+2*O(n)≈2*T(n-1)
Substituting T(n-2) with T(n-1) is allowed. In doing so you will get a higher bound which is still true for T(n-1)+T(n-2).
After the substitution you can also write T(n-1)=2*T(n-2), T(n-2)=2*T(n-3), ...
Using these values and substituting them recursively in to the T(n) you will get:
T(n)=2*2*T(n-2)
=2*2*2*T(n-3)
=2*2*2*2*T(n-4)
=...
=2^i * T(n-i)
From there you can write n-i=1 => i=n-1 and substitute the i value in T(n). You can do this because T(1)=1 is one of the base conditions.
=> T(i)=2^(n-1) * T(n-(n-1))=2^(n-1) * T(n-n+1)=2^(n-1) * T(1)=2^(n-1)
This means that the time complexity is O(2^n).

What can I use to add new value to previous value and repeat this a certain amount of times? (Javascript)

I'm trying to get an array of numbers based on a calculation that keeps adding a set amount to the previous amount until this have repeated 20 times. The initial number is a negative number because the client pays an initial amount of money for a solar power system and then the calculation should subtract an amount each month based on how much the client saves by not having to pay for electricity. It needs to be an array (I think) because it needs to go into a chart. Here's a google worksheet that might make what I'm trying to more clear. The part of the sheet that is relevant to my question is in columns T and U in pink.
I did tonne of reading on loops, different array types (reduce and map). I'm new to this so it didn't seem any of those types of arrays will do what I need to be done. I found the below code somewhere and it seemed like this is the closest to what I need to happen but I could be completely off track (my adjusted version is further down):
// program to generate fibonacci series up to n terms
// take input from the user
const number = parseInt(prompt('Enter the number of terms: '));
let n1 = 0, n2 = 1, nextTerm;
console.log('Fibonacci Series:');
for (let i = 1; i <= number; i++) {
console.log(n1);
nextTerm = n1 + n2;
n1 = n2;
n2 = nextTerm;
}
I tried to adjust it to try get it to do what I need it to do but in console it shows one number and then the rest is NAN. I know this means not a number but I don't know why or how to fix it:
function runningNetProfit(n) {
var profitSequence = [0];
var nextYear = (monthlyEstimatedSavings * 12);
for (var i = negSystemCost; i < n - 1; i++) {
profitSequence.push(nextYear);
nextYear = nextYear + profitSequence[i];
}
return profitSequence;
}
console.log(runningNetProfit(20))
I added what I did (all of the code) to a codepen as well, maybe it can make my question more clear, that can be found here The javascript relevant to this question is right at the bottom from line 145. Any advice would be much appreciated.
See if this code works for you:
It takes a given installation cost, the price they pay for electricity, and the number of months, then spits out an array with these numbers.
const installCost = 250000;
const electricityCost = 45000;
const numMonths = 20
const newArray = Array.from({length: numMonths})
const updatedArray = newArray.map((_, index) => index * electricityCost - installCost);
console.log(updatedArray) // returns [-250000,-205000,-160000,-115000,-70000,-25000,20000,65000,110000,155000,200000,245000,290000,335000,380000,425000,470000,515000,560000,605000]
Here's the code sandbox for it: https://codesandbox.io/s/blue-pine-l5rjc8?file=/src/index.js

Find number of pairs with difference larger than or equal to given number

I have a array/dict(HashMap) of positive integers.
I need to find the number of pairs that have a absolute difference greater or equal to a given number, K.
import random
import time
#given number
k = 4
# List of 2,00,000 random numbers in range 0-1000
strength = [random.randrange(0,1000) for x in range(200000)]
strength.sort()
# start clock
start1 = time.clock()
n = len(strength)
# count keeps track of number of pairs found
count = 0
for x in range(n):
for y in range(x,n):
if abs(strength[x] - strength[y]) >= k:
# if found, all number from this point to the end will satisfy
count += n-y
# So no need to go to the end
break
end1 = time.clock()
print(count)
print(end1-start1)
All the answers I find are for pairs less than or equal to a given number.
I need to find the number of pairs that have a absolute difference greater or equal to a given number, K.
Note that the total number of pairs is n * (n - 1) / 2, so if you can find the number of pairs with difference less than K, the number of pairs with difference greater than K is just n * (n - 1) / 2 - num_pairs_with_diff_less_than_K
The solution you provide is also correct (and well documented). If your question is how to adapt it to your case, then all you need to do is to use values of your HashMap (sorted) instead of the strength array.
You can get the 2 item combinations of the array and then filter / reduce them according to the difference.
One might do the job in JavaScript as follows;
Array.prototype.combinations = function(n){
return this.reduce((p,c,i,a) => p.concat(n > 1 ? a.slice(i+1).combinations(n-1).map(e => (e.push(c),e))
: [[c]]),[]);
};
function getAcordingToDiff(a,d){
return a.combinations(2)
.reduce((p,c) => Math.abs(c[0]-c[1]) >= d ? (p.push(c),p) : p ,[]);
}
var arr = Array(30).fill().map((_,i) => i+1); // array from [1,...,30]
console.log(JSON.stringify(arr))
console.log(JSON.stringify(getAcordingToDiff(arr,25))); // diff >= 25
Explanation:
So in the heart of the above code obviously lies the Array.prototype.combinations function. For those who are not familiar with JS, this is just an ordinary function that we define under the Array object's prototype (so that now every array has access to this function like arr.combinations(n)) But let's use a more expressive language and refactor the above combinations array method into a generic function.
function combinations(a,n){
var sa;
return a.reduce(function(p,c,i,a){
if (n > 1) sa = combinations(a.slice(i+1), n-1).map(e => (e.push(c),e));
else sa = [[c]];
return p.concat(sa);
},[]);
}
So as you will notice combinations(a,n) is a recursive function which takes an array a and items count n. It works on the basis of keeping the first item of the input array and recursively invoking itself with one item shorter array, combinations(a.slice(i+1), n-1), and with one less items count up until n decrements to 1 in which case it starts it's return cycle with whatever remains from the input array and each item is wrapped in an array, sa = [[c]].
So on the return cycle of the recursive calls we take the resulting array and push the kept first element (remember -> It works on the basis of keeping the first item of the input array) into each item of the returned array (remember -> ...and each item is wrapped in an array, sa = [[c]]).
So that's it... You should be able to figure out yourself the details.
However in our application we are given an array of numbers and requested to obtain only the 2 item combinations with a certain difference. In this particular case we don't need to calculate all combinations and then filter them. We can do this on the way constructing our combinations. As the required difference value d gets bigger this will bring in a huge gain over filtering afterwards method, since now as d gets bigger we are eliminating more and more of the two item combinations, even before we generate them. And... let's hard-wire our code to work with 2 items only and merge everything in a single function. The performance results are below;
function getCombosWithDiff(a, d, n = 2){
var sa;
return a.reduce(function(p,c,i,a){
if (n > 1) sa = getCombosWithDiff(a.slice(i+1), d, n-1).reduce((r,e) => Math.abs(e[0]-c) > d ? (e.push(c),r.push(e),r)
: r, []);
else sa = [[c]];
return p.concat(sa);
},[]);
}
var arr = Array(100).fill().map((_,i) => i+1);
result = getCombosWithDiff(arr,89);
console.log(JSON.stringify(arr));
console.log(JSON.stringify(result));
So that's it. I have tried the above code to list the 2 items combinations each with diff greater than 10 from an array of 1000 items. It takes like 5000 msecs in Chrome and 14000 msecs in FF. However as mentioned above, the more the diff value d gets bigger, the shorter it takes. e.g same array with diff 900 would resolve in just 1100msecs with Chrome and in 4000msecs with FF.
You can test and play here
Create a 1001-element array A of integers initialized to zeroes. Generate your random integers, and increment the appropriate index by 1 for each such integer. With some math, you could do this without generating 2,000,000 random integers, but it's not worth the complexity.
Create a second 1001-element integer B s.t. B[i] = A[0] + ... + A[i]
Answer is sum from i=0 to 1000-k of B[i] * (2,000,000 - B[i+k-1])

Javascript - return array of values that totals next number up

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.

Find the sum of consecutive whole numbers w/o using loop in JavaScript

I'm looking for a method to do calculations like:
function sumIntegerUpTo(number) {
return 1+2+3+...+number;
}
If you pass number as 5 function should return the sum of 1+2+3+4+5. I'm wondering if it's possible to do without loops.
Of course it is!
1+2+3+...+n = n * (n+1) / 2
function sumIntegerUpTo(number) {
return (1 + number) * number / 2;
}
I can think of two easy ways for me to remember this formula:
Think about adding numbers from both ends of the sequence: 1 and n, 2 and n-1, 3 and n-2, etc. Each of these little sums ends up being equal to n+1. Both ends will end at the middle (average) of the sequence, so there should be n/2 of them in total. So sum = (n+1) * (n/2).
There are as many number before the average (which is (1+n)/2) as there are after, and adding a pair of numbers that are equidistant to this average always results in twice the average, and there are n/2 pairs, so sum = (n+1)/2 * 2 * n/2 = (n+1)/2*n.
You can fairly easily extend the above reasoning to a different starting number, giving you: sum(numbers from a to b, inclusive) = (a+b)/2*(b-a+1).
Or you can use a recursive approach - which here is redundant given there is a simple formula! But there is always something cool and magical about recursion!
function addToN(n)
{
if(n==0) return 0;
else return n + addToN(n-1);
}
Edited to deal with 0!

Categories