Alternative to if else chain with range - javascript

Please check the code below
if( x > 10 && x <= 100 ){
do.something(1)
}
else if ( x > 100 && x <= 1000 ) {
do.something(2)
}
else if ( x > 1000 && x <= 10000 ) {
do.something(3)
}
else if ( x > 10000 && x <= 100000 ) {
do.something(4)
}
Is the any better alternative to this if/else or switch chain?
Can we make it configurable - so that I can keep all the conditions and corresponding action in one data-structure and write code that can pick all the conditions from that structure and do actions accordingly? This will help me keep all the conditions in a separate conf file and it will be easy to just make the edits to that and not touch the code
NOTE: These ranges may be inconsistent like 100 - 200, 345 - 956, 1000 - 1200

You could take an array and use the shor circuit of Array#some for a found range.
var value = 300;
values = [
[10, () => undefined],
[100, () => do.something(1)],
[1000, () => do.something(2)],
[10000, () => do.something(3),
[100000, () => do.something(4)]
];
values.some(([v, f]) => {
if (value <= v) {
f();
return true;
}
});

This would make it configurable.
const cond = [
{min: 10, max: 100, val: 1},
{min: 100, max: 1000, val: 2},
{min: 1000, max: 10000, val: 3},
{min: 10000, max: 100000, val: 4},
]
do.something(cond.filter(c => x > c['min'] && x < c['max'])[0]['val'])

I think it is fastest way, but not for IE check here
Yes, you can write it for example in .json or .env file, and read it.

Related

Pay with least change Javascript

I'm trying to guide my users with making cash payments. Let's say the user has two 200 dollar bills, one 100 dollar bill, one 50 dollar bill, two 10 dollar bills and three 5 dollar bill.
The user wants to pay amount of 61. The function should tell the user to pay with the bills that require the least change. This means the function should tell the user to pay with one 50, one 10 and one 5. The user will receive a change of 4.
function payWithLeastChange(amount, bills) {
let billQuantities = organizeBills(bills);
billQuantities.sort((a, b) => a.value - b.value); // sort bills in ascending order
let result = [];
for (const bill of billQuantities) {
while (amount >= bill.value && bill.quantity > 0) {
let foundBill = result.find((b) => b.value === bill.value);
if (foundBill) {
foundBill.quantity++;
} else {
result.push({ value: bill.value, quantity: 1 });
}
amount -= bill.value;
bill.quantity--;
}
}
if (amount > 0) {
return "Error: Not enough bills to make the payment.";
}
return { payment: result, change: amount };
}
function organizeBills(bills) {
let billQuantities = [];
let billValues = Array.from(new Set(bills));
for (const billValue of billValues) {
billQuantities.push({
value: billValue,
quantity: bills.filter((bill) => bill === billValue).length,
});
}
return billQuantities;
}
let amount = 61;
let bills = [200, 100, 100, 100, 50, 50, 50, 20, 20, 20, 10, 10, 10, 5, 5, 5];
let payment = payWithLeastChange(amount, bills);
console.log(payment);
I call the function like so:
let amount = 61;
let bills = [200, 100, 100, 100, 50, 50, 50, 20, 20, 20, 10, 10, 10, 5, 5, 5];
let payment = payWithLeastChange(amount, bills);
console.log(payment);
I'm expecting an output of
{ payment: [
{ value: 50, quantity: 1 },
{ value: 10, quantity: 1 },
{ value: 5, quantity: 1 }
],
change: 4 }
but instead am getting "Error: Not enough bills to make the payment." I'm stuck and can't figure out what to change in the function.
I think the idea behind the code is faulty to begin with, but I can give you some pointers along the way.
What's messing up your code is the line while (amount >= bill.value && bill.quantity > 0) { where you will only add up bills that are lower than the value. But you can get a change on $100. In fact, below are possible combinations that renders change to $63.
200 (a change of $137)
100
50+50
50+20
50+10+10
50+10+5
50+5+5+5
20+20+20+10
20+20+20+5
20+20+10+10
20+20+10+5
20+10+10+10+5
20+10+10+5+5+5
So what you need is to find all these combinations (and more), and then find a combination that have a) the least amount of change, but also b) the least amount of bills, i.e. 50+10+5.
You don't need organizeBills(). It's better to just work with the bills array, but you will need to loop through that array multiple times in one way or another.

Get range of numbers from the sorted array

There is a sorted array with numbers, for example:
const array = [100, 400, 700, 1000, 1300, 1600]
There is a function that takes two arguments as input:
function foobar(min, max) {}
The function should return the numbers from the array, starting with the first value that is >= to the min and ending with the last value that is >= to the max.
foobar(250, 1010) // returns [400, 700, 1000, 1300]
foobar(0, 15) // returns [100]
How to implement this using modern JS?
array.filter((num) => {
return num >= min && num <= max
})
Always loses the last number. 🤔
This is a perfect use-case of for...of loop.
const array = [100, 400, 700, 1000, 1300, 1600];
function foobar(array,min,max) {
let new_array = [];
for (let val of array) {
if(min<=val && val<=max) {
new_array.push(val);
} else if(val>max) {
new_array.push(val);
break;
}
}
return new_array;
}
console.log(foobar(array,0,15)); // outputs [100]
console.log(foobar(array,250,1010)); // outputs [400, 700, 1000, 1300]
It's simple, follows conventional programming paradigm and it traverses the array only once.
Here's one way
const array = [100, 400, 700, 1000, 1300, 1600];
const foobar = (min, max) => {
// get the lowest number higher than or equal to max
const lowestHigh = array.find(n => (n >= max));
const within = val => (val >= min && val <= lowestHigh);
return array.filter(within);
};
console.log( foobar(0, 150) );
console.log( foobar(400, 1500) );

How to multiply odd index?

I have a little problem with my Javascript code. Here is my question :
I want to write a function, who take in input a table of numbers. If numbers situated in even index, be returned as the way it is. But, if numbers situated in odd index, be return multiplied by his index.
For example :
Input :
[5, 10, 15, 20, 25, 30, 50, 100]
Return :
[5, 10, 15, 60, 25, 150, 50, 700]
So, my code :
function multiplyNum(numbers) {
const multiply = numbers.map(function(number) {
for (let i = 0; i < numbers.length; i++) {
if (numbers[i] % 2 == 0) {
return numbers
}
if (numbers[i] % 2 !== 0) {
return numbers
}
});
return multiplyNum
}
You don't need the for loop at all, you can get the index from the map and multiply the odd values:
function multiplyNum(numbers) {
return numbers.map(function(number, index) {
return index % 2 ? number * index : number;
});
}
console.log(multiplyNum([5, 10, 15, 20, 25, 30, 50, 100]));
You could map with a conditional operator as a check.
var array = [5, 10, 15, 20, 25, 30, 50, 100],
result = array.map((v, i) => i % 2 ? v * i : v);
console.log(result);

How to stop for in loop on if statement [duplicate]

This question already has answers here:
Searching array reports "not found" even though it's found
(1 answer)
How to stop a JavaScript for loop?
(5 answers)
Closed 4 years ago.
var enemies = [
{
nick: "Bob1",
x: 12,
y: 21
},
{
nick: "Bob2",
x: 20,
y: 21
},
{
nick: "Bob3",
x: 12,
y: 21
}
]
var me = {
x: 19,
y: 20
}
for (var x in enemies) {
var enemy = enemies[x];
if ((Math.abs(me.x - enemy.x) <= 1 && Math.abs(me.y - enemy.y) <= 1)) {
console.log("Enemy In range");
} else {
console.log("Enemies not in range");
}
}
Hello everyone. I have an array of enemies, and i am checking if some enemy is 1 field away from my x or y position. And i want to log only once if it is or it's not. As you can see now, it check for every enemy and it logs for every enemy. Which is is not what i want. I just want to simply check if there is any enemy 1 field away of my x or y position or not, and get simple response yes, or no. Im totally newbie, but if you have any hint for me, that would be awesome!
Have a boolean such as found that starts off as false. When you find it, set it to true and break. Then after the loop have if (found) ... else .... This moves the printing out of the loop, ensuring you only get it once.
Furthermore, you can compress this a lot by using the new some method, which internally does basically the same thing (just faster):
let found = enemies.some(enemy => enemyIsClose(enemy, me));
If you actually need to find which enemy is close, find instead of some will return the first one, and filter will return all of them.
You can use Array#find instead to early return from the loop if a matching element is found.
var enemies = [{
nick: "Bob1",
x: 12,
y: 21
},
{
nick: "Bob2",
x: 20,
y: 21
},
{
nick: "Bob3",
x: 12,
y: 21
}
]
var me = {
x: 19,
y: 20
}
var enemy = enemies.find(enemy => (Math.abs(me.x - enemy.x) <= 1 && Math.abs(me.y - enemy.y) <= 1));
if (typeof enemy !== undefined) {
console.log("Enemy In range");
} else {
console.log("Enemies not in range");
}
You can simply filter the object using Array.filter and find your collection.
var enemies = [
{
nick: "Bob1",
x: 12,
y: 21
},
{
nick: "Bob2",
x: 20,
y: 21
},
{
nick: "Bob3",
x: 12,
y: 21
}
]
var me = {
x: 19,
y: 20
}
var enemy=enemies.filter(item=>{
return me.x-item.x<=1
})[0];
console.log(enemy);
In order for your code to check if an enemy is nearby, it would need to iterate through all of their positions, there's no way around this but if you only want to reduce the amount of console logs you can use this code:
var isEnemyFound = true;
for (let x of enemies) {
var enemy = enemies[x];
if ((Math.abs(me.x - enemy.x) <= 1 && Math.abs(me.y - enemy.y) <= 1)) {
console.log("Enemy In range");
break;
} else {
isEnemyFound = false;
}
}
if(!isEnemyFound){
console.log("Enemies not in range");
}
Here is a better soultion, overall. The previous one I did on the fly.
Try playing around with it and see if this is what you need. I truly hope it is :)
If you change your (me - values) to '13' it's still going to be the same result, but try changing it to '14' for example, and see the how the logic plays out. This is a overkill, but if you want to advance your game, it's a great solution, because you can create as many variations and possibilities as you want, on the fly, just calling next(); in order to create the next value. Just a suggestion. Good luck!
let enemies = [
{nick: "Bob1", x: 12, y: 21},
{nick: "Bob2", x: 12, y: 21},
{nick: "Bob3", x: 12, y: 21}
];
let me = {
x: 12,
y: 21
}
function* range() {
for (let x in enemies) {
let enemy = enemies[x];
while(Math.abs(me.x - enemy.x) <=1 && Math.abs(me.y - enemy.y) <= 1) {
yield "Enemy is in range";
break; // closes iterator, triggers return
}
yield "Enemy is NOT in range";
break;
}
}
var gen = range(); // Creating a generator
console.log(gen.next().value); // Then we use it to get the next value

Always wondered how to do something like this.. Is there a easy way to find if a value exists between two values in an object?

I have been learning about ranges and also Object.keys and map, but I am wondering if this is possible:
{
"zero": 0,
"ten": 10,
"twenty": 20,
"thirty": 30
}
Given a number between 0 and 30, is there a way to determine what two numbers it is between?
For example,
Object.keys(range).map((v) => {
if (15 > range[v] && 6 < range[v+1]) {
// print out lower and upper
}
});
It is not such a good idea to use a non-Array object for range:
The property names do not add much to the meaning of the object
The order in which property names are iterated is a complex issue, and better not relied upon.
Better would be to use an array, and then use the find or findIndex method:
function getInterval(range, n) {
var i = range.findIndex( i => n < i );
if (i < 0) i = range.length;
// return an array with the two values that "bound" the value:
return [range[i-1], range[i]];
}
var range = [0, 10, 20, 30];
// Examples: note that one value can be undefined, when outside of the range
console.log('-2: ' + JSON.stringify(getInterval(range, -2)));
console.log('6: ' + JSON.stringify(getInterval(range, 6)));
console.log('15: ' + JSON.stringify(getInterval(range, 15)));
console.log('31: ' + JSON.stringify(getInterval(range, 31)));
You could check the interval and print the key.
var range = { zero: 0, ten: 10, twenty: 20, thirty: 30 },
interval = [15, 25];
Object.keys(range).forEach(v => interval[0] < range[v] && range[v] < interval[1] && console.log(v));
A different approach with a single value for an interval of the object properties
var range = { zero: 0, ten: 10, twenty: 20, thirty: 30 },
value = 15;
Object.
keys(range).
sort((a, b) => range[a] - range[b]).
forEach((k, i, kk) => (range[kk[i - 1]] <= value && value <= range[k] || range[k] <= value && value <= range[kk[ i + 1]]) && console.log(k));

Categories