Related
I have two numbers like ESP1 and ESP2.
In my DB there are many data to the ESP1 & ESP2, ESP1 is minimum values and ESP2 is maximum value.
i need to generate intervals between those two number in multiplies of 10, for example.
ESP1 = 0 and ESP2 = 83
my result should be [0,10,20,30,40,50,60,70,80].
how to write code for this in js
Just use a for loop:
function generateIntervalsOf(interval, start, end) {
const result = [];
let current = start;
while (current < end) {
result.push(current);
current += interval;
}
return result;
}
generateIntervalsOf(10, 0, 83) // [0, 10, 20, 30, 40, 50, 60, 70, 80]
Another solution
const a = 0;
const b = 83;
const result = _.range(a, b, 1).filter(item => item%10 == 0);
console.log(result)
Use either a for or while loop. There are two approaches you could take.
A: Brute force. Count up from the start number to the end number and store every multiple of ten.
const results = [];
for (let i = ESP1; i <= ESP2; i++) {
if (i %10 === 0) {
results.push(i);
}
}
B: Cleverness. Brute force might be slow if you were doing this over a very large range. Instead of going through every single number, we only need the multiples of ten. So, in short, we just need the next multiple of ten after ESP1, and we add ten until we exceed ESP2.
e.g.
const results = [];
const floor = ESP1 + 10 - ESP1 % 10;
// i.e. if ESP1 is 13, add 10 to get 23, and then subtract 3 to get 20
for(let i = floor; i < ESP2; i+= 10) {
results.push(i);
}
If we ran this with ESP1 = 3 and ESP2 = 56, we would get the result [10, 20, 30, 40, 50]. This approach will go through 1/10 as many iterations as approach A, since we're counting by tens.
I have set of numbers; example: [12, 13, 15, 18]. From which I have to find the elements whose sum is a specific "total value", for example: 25 is 12 + 13.
Edit: First of all thank you all for your valuable feedback but i think many of you misunderstood my question! My question is not just for "two combination" but for more than two. For example:
1 2 3 4 5 6 7 8 9 10 100
From the above list we need to get "119" here we need more than "two combination".
How can i write the code through bash script or JavaScript?
Kindly help.
You could take a recursive approach and check every combination by using a short circuit for sums wich are greater than the given sum.
function getSum(numbers, sum) {
function iter(index, right, left) {
if (!left) return result.push(right);
if (left < 0 || index >= numbers.length) return;
iter(index + 1, [...right, numbers[index]], left - numbers[index]);
iter(index + 1, right, left);
}
var result = [];
iter(0, [], sum);
return result;
}
getSum([12, 13, 15, 18], 25).forEach(a => console.log(...a));
console.log('--')
getSum([1, 2, 3, 4, 5], 10).forEach(a => console.log(...a));
let orgArr=[12,13,14,11,15,18];
orgArr.filter((each,i,orgArr)=>orgArr[i+1]!==undefined?each+orgArr[i+1]===25?console.log(each,"..",orgArr[i+1]):"":"")
it will give you the pair which sum is 25
You can do something simple using indexOf method.
function findComb(arr, sum) {
for (let i = 0; i < arr.length - 1; i++) {
let j = arr.indexOf(sum - arr[i], i);
if (j !== -1) {
return [arr[i], arr[j]]
}
}
}
console.log(findComb([12, 13, 15, 18], 25))
Note : Will return only the first combination and limited to 2 numbers.
bash version:
#!/usr/bin/env bash
function find_sum {
local sum=$1 first=$2; shift 2
while test $# -gt 0; do
for c; do
if test $sum = $(($first + $c)); then
echo $sum = $first + $c
fi
done
first=$1; shift
done
}
find_sum 25 15 12 13 18
Find all combinations using indexOf and Set to stock unique values:
function findComb(total, arr) {
const output = new Set([]);
arr.forEach((el, index) => {
const i = arr.indexOf(total - el, index);
if(i > -1) { output.add(el); output.add(arr[i]); }
});
return [...output];
}
console.log(findComb(25, [12, 13, 15, 18]));
console.log(findComb(25, [12, 13, 7, 15, 18, 12]));
It is a variant of the knapsack problem, try to google for it. You can find the solution recursively in 2^n, or in n^2 using two-dimensional array for storing partial results.
I find a way to achieve the above question. I have used at the beginning the codes snippets above, but the problem with them is that they were failing when using very big numbers. The only limitation in my solution below that it's responding with only one result. However, running the code again, will most probably give another result.
My method below will work easily also with big numbers.
Give it a try.
var total = 0;
var transactions = [];
/**This is very important line, it limit the tries to a specific number,
after that, it will consider no combinations**/
var limit_tries = 100000;
function shuffle (numbers){
return numbers.sort((a, b) => 0.5 - Math.random());
}
function getSum(numbers, sum) {
//Sorting the Array
var newArray = numbers.sort((a, b) => a - b);
//Print the Array After Cleaning
while (total != sum && limit_tries > 0){
for (var i=0;i<newArray.length;i++){
if (total<sum){
total = total + newArray[i];
transactions.push(newArray[i]);
}
}
if (total!=sum){
transactions.length = 0;
shuffle(newArray);
total = 0;
limit_tries = limit_tries - 1;
} else if (total=sum){
console.log (transactions);
total= 0;
transactions.length = 0;
limit_tries = 1000000;
break;
}
}
}
//Try 1
getSum([5,1,22,55,12,34,22,12,54,6,5,23,1,2,6,8,22,45,23,33,15,65,12,90,12,7,8,9,1], 99);
//Try 2
getSum([5,1,22,55,12,34,22,12,54,6,5,23,1,2,6,8,22,45,23,33,15,65,12,90,12,7,8,9,1], 99);
//Try 3
getSum([5,1,22,55,12,34,22,12,54,6,5,23,1,2,6,8,22,45,23,33,15,65,12,90,12,7,8,9,1], 99);
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 6 years ago.
Improve this question
Given a number, how can I find the nearest two numbers which starts with 1, 2.5 or 5? (10, 25, 50, 100, 250, 500, 1000...endless)
The result should be the nearest nearest higher number, and one below it.
For example: the number 420 should return 250 and 500.
For example: the number 10 should return 10 and 25.
Can use Lodash if it's helpful.
Thanks.
OK, I think I understand based on your comments.
// Finds the two numbers on each side for any number.
function nearest(n) {
let m = multiplier(n);
return nearest10(n / m).map(n => n * m);
}
// Finds the two numbers on each side for numbers between 1 and 10.
function nearest10(n) {
return n < 2.5 ? [1, 2.5] : n < 5 ? [2.5, 5] : [5, 10];
}
// Returns the neareast power of 10 less than or equal to n.
function multiplier(n) {
return Math.pow(10, Math.floor(Math.log10(n)));
}
And here is a sample of the results:
console.log(nearest(2)); // [1, 2.5]
console.log(nearest(420)); // [250, 500]
console.log(nearest(79310)); // [50000, 100000]
First write the number in scientific notation to get rid of the scale.
420 = 4.2x10^2
Then locate the mantissa among [1, 2.5), [2.5, 5), [5, 10).
4.2 in [2.5, 5)
And transfer the exponent,
2.5x10^2 = 250, 5x10^2 = 500
This is better done using base 10 logarithms,
L= log(X) / log(10)
E= floor(L)
L= L - E
if L < log(2.5), LB= pow(10, N), UB= 2.5 * pow(10,N)
else if L < log(5) , LB= 2.5 * pow(10, N), UB= 5 * pow(10,N)
else LB= 5 * pow(10, N), UB= 10 * pow(10,N)
function findPrevAndNext(x){
// returns the next highest value and previous
// lower value in the infinite series
// [1, 2.5, 5, 10, 25, 50, 100, ...]
var top = 5;
while(top < x){
top = top * 10;
}
var mid = top / 2; // ex: 5/2 = 2.5
var bot = top / 5; // ex: 5/5 = 1
var prev, next = 0;
if(x >= mid){
prev = mid;
next = top;
}
else if(x >= bot){
prev = bot;
next = mid;
}
else{
prev = bot / 2;
next = bot
}
return Array(prev,next);
}
https://jsfiddle.net/o44t0t65/1/
I have a list of FICO scores that I'd like to group depending on their value, with groups starting at 0-620, then 620-640, incrementing by 20 every time.
What it should return is a count of values in each group -- 0-620, 620-640, 640-660, 660-680, etc. up to 780-800.
I'm currently using _.countBy but it returns a count for every unique number, rather than for every group.
var counts = _.countBy(ficos, function(x) { return x });
//Counts should be {620: 22, 625: 19, 655: 24, 670: 20, 690: 30, 720: 29, 734: 17, 760: 21, 790: 18}
Is there a way to take advantage of _.countBy or some other function? I'm trying to avoid a long if statement, if possible.
So return the appropriate groups then:
function (x) {
if (x < 620) return '<620';
if (x >= 800) return '>800';
var lower = Math.floor(x / 20) * 20,
higher = lower + 20;
return lower + '-' + higher;
}
Here's an arithmetical puzzler for you StackOverflowers. I'm working on a JS game that'll allow someone to enter their name and will generate another name based on what they enter. Sort of like this. Basically every time someone enters a particular string, I want to generate the same other string by taking items from a list.
So I have an array of words, numbering 20 in this example
"nouns": [
"Nitwit",
"Cretin",
"Village Idiot"
// ..
]
When the user inputs their name, I convert each ASCII alphabetic character to a digit. I'm going to add up all the resulting digits and use the total to select one of the words from my array.
// Convert alpha chars to numerical equivalents
function str2num (mystr) {
mystr = mystr.toUpperCase();
var conv = [],
l = mystr.length,
regex = /^[A-Za-z]+$/;
for (var i = 0; i < l; i++) {
if (regex.test(mystr.charAt(i))) {
conv.push(mystr.charCodeAt(i) - 64);
}
}
var c = conv.length,
sum = 0;
for (var j = 0; j < c; j++) {
sum += conv[j];
}
return sumDigits(sum);
}
Since there are only 20 elements in the word array, I always want the sum to be less than 20. So if it's equal or greater than 20, I want to add up its digits again. This is how I'm currently doing it.
// Recursively add digits of number together
// till the total is less than length of word list
function sumDigits (number) {
var listLength = adjectives.length;
var sum = number % listLength;
if (number > listLength) {
var remainder = Math.floor(number / 10);
sum += sumDigits(remainder);
}
if (sum > listLength) {
sum = sumDigits(sum);
}
return sum;
}
And when I've got a result below 20, I return the value of nouns[sum] to the user. This code pretty much works - the resulting sum is always below the maximum allowed. But the result isn't very random - it seems that I'm getting a disproportionate number of sums in the lower end of the 0 to 20 range. I don't want users to keep seeing words from the beginning of my list. Is there any change I can make to sumDigits that will ensure an even spread of results? Or is this already correct? (I've done this JSFiddle to demo what I'm talking about.)
I would make it dependent on the charcode of the characters in the name:
function getValue(name) {
var letters = name.toLowerCase().split(''),
value = 0,
i = 0;
for(; i < letters.length; i ++) {
value += letters[i].charCodeAt(0);
}
return value % 20;
}
The output sum in your current implementation is indeed not uniformly distributed.
As an example, consider all the numbers with one or two digits (1 - 99):
1 of them is summed up to 1 ( 1)
2 of them are summed up to 2 ( 2, 20)
3 of them are summed up to 3 ( 3, 30, 21)
4 of them are summed up to 4 ( 4, 40, 31, 22)
5 of them are summed up to 5 ( 5, 50, 41, 32, 23)
6 of them are summed up to 6 ( 6, 60, 51, 42, 33, 24)
7 of them are summed up to 7 ( 7, 70, 61, 52, 43, 34, 25)
8 of them are summed up to 8 ( 8, 80, 71, 62, 53, 44, 35, 26)
9 of them are summed up to 9 ( 9, 90, 81, 72, 63, 54, 45, 36, 27)
9 of them are summed up to 10 (10, 91, 82, 73, 64, 55, 46, 37, 28)
9 of them are summed up to 11 (11, 92, 83, 74, 65, 56, 47, 38, 29)
8 of them are summed up to 12 (12, 93, 84, 75, 66, 57, 48, 39)
7 of them are summed up to 13 (13, 94, 85, 76, 67, 58, 49)
6 of them are summed up to 14 (14, 95, 86, 77, 68, 59)
5 of them are summed up to 15 (15, 96, 87, 78, 69)
4 of them are summed up to 16 (16, 97, 88, 79)
3 of them are summed up to 17 (17, 98, 89)
2 of them are summed up to 18 (18, 99)
1 of them is summed up to 19 (19)
This is probably closer to Normal Distribution than to Uniform Distribution.
In order to achieve the latter, simply return sum % c instead of sumDigits(sum).
I think sumDigits function returns a biased number. Do not return sumDigits(sum). Instead you can return sum % 20.
fzzle's answer is a good one.
Alternatively, you could do a sum reduction with a while:
var reduced = sum;
while(reduced > 20){
reduced -= name.length;
}
This is a more complete example:
var sum = 0;
var name = 'John Smith'.split('');
for(var k in name){
sum += name[k].charCodeAt(0);
}
var key = sum;
while(key > 20){
key -= 'John Smith'.length;
}
If you test it you'll see it produced a different results to sumDigits % 20. Mind you, I don't know how this method will behave with unusually long names. Let me test it.
Confirmed. XD
I tried with John Smith John Smith John Smith John Smithxx and broke it. Don't think this qualifies as an answer now. :(