get range from the nearest number in javascript - javascript

I have one range object and another is price_values array, now I want to nearest range from the range object for each value of price_values array. I have tried the below solution but it's not given me the proper range.
range = {
0: '25-500',
1: '1500-2500',
2: '5000-10000'
}
let price_values = [5, 100, 1500, 7000, 15000]
I tired below solution
let nearestPriceRangeArr = [];
let rangeLength = Object.keys(range).length;
Object.keys(range).forEach(key => {
price_values.forEach((price, qKey) => {
let rangeArr = key.split("-");
let fromRange = parseInt(rangeArr[0]);
let toRange = parseInt(rangeArr[1]);
if(price <= fromRange) {
if(x == 0) {
nearestPriceRangeArr[price] = key;
}
} else {
if (price >= fromRange && price <= toRange) {
nearestPriceRangeArr[price] = key;
} else {
if(price >= toRange) {
let ab = (x == rangeLength - 1) ? key : key;
nearestPriceRangeArr[price] = ab;
}
}
}
x++;
});
});
Expected Output
nearestPriceRangeArr[5] = '25-500';
nearestPriceRangeArr[100] = '25-500';
nearestPriceRangeArr[1500] = '1500-2500';
nearestPriceRangeArr[7000] = '5000-10000';
nearestPriceRangeArr[15000] = '5000-10000';

You could take an array of ranges and find the range by checking the price.
const
range = ['25-500', '1500-2500', '5000-10000'],
prices = [5, 100, 1500, 7000, 15000],
result = Object.fromEntries(prices.map(p => [p, range.find((r, i, { length }) => {
const [low, high] = r.split('-').map(Number);
return p <= high || i === length - 1;
})]));
console.log(result);

Don't know what I did, but its strange solution for your strange problem.
console.clear();
let range = {
0: '25-500',
1: '1500-2500',
2: '5000-10000'
}
let price_values = [5, 100, 1500, 7000, 15000];
let nearestPriceRangeArr = {};
let rangeValues = Object.values(range);
price_values.forEach((price)=>{
// for prices which are in one the range_values
rangeValues.forEach((range, rangeIndex)=>{
let ranges = range.split('-');
if(price >= parseInt(ranges[0]) && price <= parseInt(ranges[1])){
nearestPriceRangeArr = {
...nearestPriceRangeArr,
[price] : range
}
}
/* if price is not falling in any range */
// if price is smaller than first range
if(rangeIndex === 0){
if(price <= ranges[0]){
nearestPriceRangeArr = {
...nearestPriceRangeArr,
[price] : range
}
}
} else {
// if price is greater than previous range
// and smaller than current range
const previousRanges = rangeValues[rangeIndex - 1].split("-");
if(price > previousRanges[1] && price <= ranges[0] ){
nearestPriceRangeArr = {
...nearestPriceRangeArr,
[price] : range
}
} else {
// if price is greater than last range
if(price > ranges[1]){
nearestPriceRangeArr = {
...nearestPriceRangeArr,
[price] : range
}
}
}
}
})
})
console.log(nearestPriceRangeArr);
console.log(nearestPriceRangeArr[5])
console.log(nearestPriceRangeArr[100])
console.log(nearestPriceRangeArr[1500])
console.log(nearestPriceRangeArr[7000])
console.log(nearestPriceRangeArr[15000])

Related

Randomising arrays to form an highly entropic grid

I am attempting to make a 5x5 grid using arrays with the following limitations
Should not exceed more than 4 check marks per grid
Should not have 2 consecutive check marks
This is what I have come up with so far, I would appreciate if someone could help me figure out how would I achieve the latter condition
let emoji = {
0: '✅',
1: '❓',
}
let grid = []
let checkmarks = 0
for (let i = 0; i < 5; i++) {
let row = []
for (let j = 0; j < 5; j++) {
let random = crypto.randomInt(0, 1000) % 2
if (random == 0) {
if(checkmarks < 4) {
row.push(emoji[0])
checkmarks++
}
else {
row.push(emoji[1])
}
} else {
row.push(emoji[1])
}
}
grid.push(row)
}
I am attempting to make it as random as possible.
I'm posting this answer because the accepted answer doesn't seem to produce a consistent result. I agree with most of the approach, but result just wasn't always returning 4 checkmarks (because it seems to reset after each iteration, which can increase the maximum number of loops needed).
But ultimately, the idea is to fill the 5x5 array with the ❓ character first, randomly select a location, verify the surrounding blocks are not ✅, and then place a ✅ if these conditions are met. If not, I instead just select a new position but keep the existing results until the needed number of ✅ have been set.
let grid = [],
rows = 5,
cols = 5,
maxChecks = 4,
totalChecks = 0,
emoji = {
0: '✅',
1: '❓',
};
const _RandomChecks = () => {
grid = [];
totalChecks = 0;
for(let i = 0; i < rows; i++) {
grid[i] = [];
for(let j = 0; j < cols; j++) {
grid[i] = [...grid[i], emoji[1]];
}
}
while(totalChecks < maxChecks) {
let rndRow = parseInt(crypto.randomUUID().replace(/[^0-9]/g, "").substr(-8)) % rows,
rndCol = parseInt(crypto.randomUUID().replace(/[^0-9]/g, "").substr(-8)) % cols,
valid = (grid[rndRow][rndCol] == emoji[1]) ? true : false;
if(grid[rndRow-1]?.[rndCol] && valid) valid = (grid[rndRow-1]?.[rndCol] == emoji[1]) ? true : false;
if(grid[rndRow+1]?.[rndCol] && valid) valid = (grid[rndRow+1]?.[rndCol] == emoji[1]) ? true : false;
if(grid[rndRow][rndCol-1] && valid) valid = (grid[rndRow][rndCol-1] == emoji[1]) ? true : false;
if(grid[rndRow][rndCol+1] && valid) valid = (grid[rndRow][rndCol+1] == emoji[1]) ? true : false;
if(valid) {
grid[rndRow][rndCol] = emoji[0];
totalChecks++;
}
}
console.log(grid.map(row => row.join('')).join('\n'));
}
_RandomChecks();
Instead of randomly determining if a cell should be a checkmark I would rather randomly find cells that should be a checkmark.
Your current solution decreases the chance of getting a checkmark with each cell.
Created some example code for you:
const emojis = ['✅', '❓']
const size = 5
const checkmarks = []
for (let i = 0; i < 4; i += 1) {
while (true) {
// get random x and y
const x = Math.random() * size | 0
const y = Math.random() * size | 0
// check if x and y are far enough from existing checkmarks
const areNeighbours = checkmarks.some(c => {
if (c.x === x) {
return Math.abs(c.y - y) <= 1
}
if (c.y === y) {
return Math.abs(c.x - x) <= 1
}
return false
})
if (!areNeighbours) {
checkmarks.push({
x,
y
})
break
}
}
}
const grid = []
for (let y = 0; y < size; y += 1) {
grid.push([])
for (let x = 0; x < size; x += 1) {
const checkmark = checkmarks.find(c => c.x === x && c.y === y)
grid[y][x] = checkmark ? emojis[0] : emojis[1]
}
}
console.log(grid.map(row => row.join('')).join('\n'))
Imagine a 5x5 board initially filled by ❓.
Next you toss 4 coins at once, each coin will landed in one cell, head or tail.
If head, place a ✅ in the cell.
Now check if non-consecutive ✅ condition is met. If not start over.
Solution:
const emojis = ['✅', '❓'];
function randomInt(min, max) {
return min + Math.floor(Math.random() * (max - min));
}
function tossCoins(checkmarkLimit, size) {
const positions = Array.from({ length: checkmarkLimit }, () => {
const pos = randomInt(0, size * size);
const tail = Math.random() > 0.5;
if (tail) return null;
const x = pos % 5;
const y = (pos - x) / 5;
return [x, y];
})
return positions.filter(Boolean);
}
function checkNonConsecutive(positions) {
for (let i = 0; i < positions.length; i++) {
const p = positions[i];
for (let j = 0; j < positions.length; j++) {
if (i == j) continue;
const o = positions[j];
const distance = Math.abs(p[0] - o[0]) + Math.abs(p[1] - o[1])
if (distance <= 1) {
return false;
}
}
}
return true;
}
function main() {
const checkmarkLimit = 4;
const size = 5;
const grid = Array.from({ length: size }, () => Array.from({ length: size }, () => emojis[1]));
let positions = tossCoins(checkmarkLimit, size);
while (!checkNonConsecutive(positions)) {
positions = tossCoins(checkmarkLimit, size);
}
positions.forEach(([x, y]) => {
grid[y][x] = emojis[0];
});
return grid;
}
for (let n=0; n < 10; n++) {
console.log('round: ' + n);
console.log(main().map(row => row.join('')).join('\n'));
}

generate random numbers in specific range and using specific numbers?

How to generate random numbers in specific range and using specific numbers?
Example
given numbers [7,8];
given range [100-900];
output must be one of them 777, 787, 788, 878, 877, 888 etc...
Help me
const randomGenerateNumber = (maxRange:number, minRange:number, numbers:number[]) => {
//...what should i do in there??? Help me? Any Idea?
}
I think you don't want random numbers. It seems that you want a set of numbers based on some rules. Random means something else.
If I understand well your question you want to generate all possible numbers containing only a set of digits from a range of numbers. Is this an accurate description?
If so, this is similar with what you want: Generate random numbers only with specific digits
Edit:
You are right, so you want only one number.
In javascript you could do something like this:
I edited the algorithm to take into account min and max in probably the most lazy way. I didn't take into account cases where numbers can't be generated, it will return undefined.
There are so many ways to do this. Your algorithm can work too and maybe more efficient but it seems to have an issue with 0, it will generate numbers with 0 even if it's not in the digits array.
function randomGenerateNumber(minRange, maxRange, digits){
noTries = 0;
while(noTries++ < 100000)
{
var num = 0;
//get a random number from your range
len = Math.floor(Math.random() * (maxRange - minRange) + minRange);
//get the lenght of that random number
len = len.toString().length;
//generate a number with that length using only your set of digits
while(len--)
{
num = num * 10 + digits[Math.floor(Math.random() * digits.length)];
}
if(num >= minRange && num<= maxRange)
{
return num;
break;
}
}
}
//your testing cases
console.log(randomGenerateNumber(100,900,[7,8]))
console.log(randomGenerateNumber(299,300,[1,2,3,4,5,6,7,8,9]));
i did it. Is there any improvement. Little bit messy.
const getRandomNumber = (min: number, max: number, numbers: number[]): number => {
if (numbers.length === 9) {
return Math.floor(Math.random() * (max - min + 1) + min);
}
let result = '';
//split maxDigits 100 => [1, 0, 0]
const maxDigits = max
.toString()
.split('')
.map(i => parseInt(i, 10));
//split minDigits 100 => [1, 0, 0]
const minDigits = min
.toString()
.split('')
.map(i => parseInt(i, 10));
//length of random number [minDigit, maxDigit] inclusive
const randomDigit = Math.floor(Math.random() * (maxDigits.length - minDigits.length + 1) + minDigits.length);
let alreadyHigh = false;
let alreadyLow = false;
let equal = true;
//4 conditions
//1. minDigits.length === maxDigits.length
//2. randomDigit === minDigits.length
//3. randomDigit === maxDigits.length
//4. randomDigit > minDigits.length && randomDigit < maxDigits.length
for (let i = 0; i < randomDigit; i++) {
const numbersToUse = i === 0 ? numbers : [...numbers, 0];
let availableNumbers = [];
if (minDigits.length === maxDigits.length) {
if (equal) {
for (let k = 0; k < numbersToUse.length; k++) {
if (minDigits[i] > maxDigits[i]) {
if (numbersToUse[k] >= 0 && numbersToUse[k] <= maxDigits[i]) {
availableNumbers.push(numbersToUse[k]);
}
} else if (numbersToUse[k] >= minDigits[i] && numbersToUse[k] <= maxDigits[i]) {
availableNumbers.push(numbersToUse[k]);
} else {
availableNumbers.push(maxDigits[i]);
}
}
} else {
if (!alreadyHigh) {
for (let k = 0; k < numbersToUse.length; k++) {
if (numbersToUse[k] >= minDigits[i]) {
availableNumbers.push(numbersToUse[k]);
}
}
} else {
availableNumbers = numbersToUse;
}
}
} else if (randomDigit === minDigits.length) {
if (!alreadyHigh) {
for (let k = 0; k < numbersToUse.length; k++) {
if (numbersToUse[k] >= minDigits[i]) {
availableNumbers.push(numbersToUse[k]);
}
}
} else {
availableNumbers = numbersToUse;
}
} else if (randomDigit === maxDigits.length) {
if (!alreadyLow) {
for (let k = 0; k < numbersToUse.length; k++) {
if (numbersToUse[k] <= maxDigits[i]) {
availableNumbers.push(numbersToUse[k]);
}
}
} else {
availableNumbers = numbersToUse;
}
} else {
availableNumbers = numbersToUse;
}
availableNumbers = [...new Set(availableNumbers)];
const randomIndex = Math.floor(Math.random() * availableNumbers.length);
result += `${availableNumbers[randomIndex]}`;
alreadyHigh = !alreadyHigh ? availableNumbers[randomIndex] > minDigits[i] : true;
alreadyLow = !alreadyLow ? availableNumbers[randomIndex] < maxDigits[i] : true;
equal = equal ? availableNumbers[randomIndex] === maxDigits[i] : false;
}
return parseInt(result, 10);
};

How to solve a Box Claw mover so it spread all boxes evenly on all available stacks?

I'm trying to solve a Robotic Claw lever puzzle, which should spread all boxes across all available stacks evenly.
The problem is that when it reaches the last box, it moves LEFT and then RIGHT, looping infinitely.:
function solve(clawPos, boxes, boxInClaw) {
// Calculate a maximum number of boxes per stack
let max = (boxes.reduce((a, b) => a + b) + ~~boxInClaw) / boxes.length
// Current stack number
const current = boxes[clawPos]
// Helpers
const bigger = current > max
const lower = current < max
const equal = current === max
const last = clawPos === boxes.length - 1
// Command to return for a claw
let command = ''
// Actions for claw
const R = () => command = 'RIGHT'
const L = () => command = 'LEFT'
const U = () => command = 'PICK'
const D = () => command = 'PLACE'
// Automatically select where to move the claw
const autoDirection = () => {
const value = boxes[clawPos]
const left = boxes.slice(0, clawPos)
const right = boxes.slice(clawPos, -1)
const target = max - 1
if (boxInClaw) {
if (left.includes(target)) L()
else if (right.includes(target)) R()
} else {
R()
}
}
autoDirection()
if (boxInClaw) {
if (lower) D()
} else {
if (bigger) U()
}
return command;
}
I've tried to many different approaches to make it dynamic, is there any smarter approach to know at which direction it should go?
Here is a direct link (please, DO NOT submit): https://www.codingame.eu/evaluate/18917274?id=427696529803c1cd24e9258b89d01a98a72126e
This is my solution to that:
function createStack(length, totalBoxes) {
const boxPerStack = Math.floor(totalBoxes / length);
let newStack = new Array(length).fill(boxPerStack);
const remainder = totalBoxes % length;
if (remainder !== 0) {
for (let i = 0; i < remainder; i++) {
newStack[i]++;
}
}
return newStack;
}
function solve(clawPos, boxes, boxInClaw) {
// Write your code here
const totalBoxes = boxes.reduce((prev, acc) => prev + acc);
let targetPos;
if (boxInClaw) {
const targetStack = createStack(boxes.length, totalBoxes + 1);
// Move to place
for (let i = 0; i < boxes.length; i++) {
if (boxes[i] < targetStack[i]) {
targetPos = i;
break;
}
}
if (clawPos === targetPos) return 'PLACE';
else if (clawPos < targetPos) return 'RIGHT';
else return 'LEFT';
} else {
const targetStack = createStack(boxes.length, totalBoxes);
// Move to pick
for (let i = 0; i < boxes.length; i++) {
if (boxes[i] > targetStack[i]) {
targetPos = i;
break;
}
}
if (clawPos === targetPos) return 'PICK';
else if (clawPos < targetPos) return 'RIGHT';
else return 'LEFT';
}
return '';
}

I am unable to get my Javascript getMaxLetter problem to show correct results

Hi! for my class I had to create a javascript function that returns a maxCharacter and how many times it shows up. -- The problem is this function will print out how many times the maxCharacter shows up but not print "maxChar" only "max" will print out. Here is the function:
const getMaxLetter = (str) => {
let max = 0;
let maxChar = '';
str.split('').forEach((char) => {
if (str.split(char).length > max) {
max = str.split(char).length;
maxChar = char;
}
});
return `The max letter is : ${maxChar} and the max number of times it is seen is: ${max}`;
};
Your "max char" is a space... just add
if (char === ' ') return;
const getMaxLetter = (str) => {
let max = 0;
let maxChar = '';
str.split('').forEach((char) => {
if (char === ' ') return;
if (str.split(char).length - 1 > max) {
max = str.split(char).length - 1;
maxChar = char;
}
});
return `The max letter is : ${maxChar} and the max number of times it is seen is: ${max}`;
};
console.log(getMaxLetter('Abcde f ghhai f kh f k'))

Subset sum with number reuse allowed

I have a list of positive integers e.g. 15, 29, 110, and a target e.g. 44. I'm trying to find all possible combinations which sum to the target but importantly, the numbers in the set can be used multiple times e.g.
Target = 44
Result = 1x15, 1x29
Target = 307
Result = 2x110, 3x29
I found a dynamic programming solution which works when the combination is no more than one of each number. So Target 44 works but not my 307 example (returns Not Found).
How can the multiples or number reuse be done?
function subset(people, min, max)
{
var subsets = [];
subsets[0] = '';
for (var person in people)
{
for (var s = min-1; s >= 0; --s)
{
if (s in subsets)
{
var sum = s + people[person];
if (!(sum in subsets))
{
subsets[sum] = subsets[s] + ' ' + person;
if (sum >= min && sum <= max)
{
return subsets[sum];
}
}
}
}
}
return 'Not found';
}
var p = {
optionA:15,
optionB:29,
optionC:110
};
var qty = 307;
console.log(subset(p, qty, qty));
Try this recursive solution:
function subset(people, min, max) {
const pairs = Object.entries(people),
results = [],
getSum = multiplications => multiplications.reduce((sum, multiplicator, position) =>
sum + pairs[position][1] * multiplicator, 0),
formatResult = result => result.map(multiplications =>
multiplications.reduce((res, multiplicator, position) =>
(multiplicator > 0 ? res.push(`${multiplicator}x${pairs[position][1]}`) :
res, res), []));
function findSums(multiplications, position) {
let s;
while((s = getSum(multiplications)) <= max) {
if (s >= min) {
results.push([...multiplications]);
}
if (position < pairs.length - 1) {
const m = [...multiplications],
nextPosition = position + 1;
m[nextPosition]++;
findSums(m, nextPosition);
}
multiplications[position]++;
}
}
findSums(pairs.map(_ => 0), 0);
return results.length > 0 ? formatResult(results) : "Not found";
}
var p = {
optionA:15,
optionB:29,
optionC:110
};
var qty = 307;
console.log(subset(p, qty, qty));
Change the second loop in such way:
for (var s = 0; s <= wantedSum - people[person] ; s++)
Using this approach you fill all entries of subsets[] array\list where index is multiple of people[person] (instead of single entry). For example, with value 3 you fill 3,6,9,12... entries.

Categories

Resources