Find immediate less value from object or map using JS - javascript

object -> let error = {3:1, 4:1, 10:2, 12:1, 13:2} or {3:1, 4:1, 12:1, 13:2}
map -> let map = new Map([[3,1],[4,1],[10,2],[12,1],[13,2]]}
if my number is 10 means I need to get the value of 4 ie immediate less and if no less value then I need to return largest value.
for now, I will decrement the value and check if the exists in the map and return the value. Currently, I am using an object. If the passed number exists or not need to find immediate less value.
my obj contains 1, 3, 7, 10 is my keys and 5 is the number passed and I need to find the immediate less value 3 < 5 . if value passed 7 also 3<7. it is not based on index. its based on keys.
myFunction = (number) => {
let index;
for(int i = number; i>=number ; i--){
if(error[i] != undefined){
index = i;
break;
}
}
return index;
}
Is there any better way to do the same ?

You can sort the values in descending order and then use find the first value which is less than number, if the value is found return that value else return the last value
let mapper = [[3,1],[4,1],[10,2],[12,1],[13,2]].sort((a,b)=>b[0]-a[0])
let myFunction = (number) => {
let value = mapper.find((v, i) => {
if (v[0] < number) {
return v[1]
}
})
return value || mapper[0]
}
console.log(myFunction(10))
console.log(myFunction(9))
console.log(myFunction(2))

You could take the number directly and decrement the value until it reaches zero.
function fn(number) {
while (number--) if (number in error) return number;
}
var error = { 3: 1, 4: 1, 10: 2, 12: 1, 13: 2 };
console.log(fn(9));
console.log(fn(10));

Related

Given an array of integers elements, find such t that cyclic t-shift operation turns elements into a sorted array If there is no such t, return -1

The solution that i've been working on so far:
function solution(elements) {
let numOfShifts;
let shift = shiftedArray(elements);
for(i = 0; i < shift.length; i++){
//Here is where i'm getting stuck... how do i continue through the loop even after the first false is returned
//until all arrays are checked for equality?
if(areEqual(shift[i])){
numOfShifts = i
}else return -1;
}
return numOfShifts;
};
function shiftedArray(array){
let shiftedArrays = [];
for(let i = array.length -1 ; i >= 1; i--){
// first element is simply a formula to create chunk 1
let firstElement = array.length - (i % array.length);
//the result of first element.
let chunk1 = array.slice(firstElement);
//the remaining numbers
let chunk2 = array.slice(0, firstElement);
//Copy of both chunks now merged and pushed into shifted arrays
shiftedArrays.push([...chunk1, ...chunk2]);
};
return shiftedArrays;
}
function areEqual(shift){
let sortedShift = [...shift].sort((a ,b) => {
return a - b
});
//takes in a single shift and does a deep check to see if the array is equal to sorted version
if(sortedShift.length === shift.length){
return sortedShift.every((element, index) => {
if(element === shift[index]){
return true;
}
return false;
})
}
}
console.log(solution([1,4,2,3]));
console.log(solution([[2, 3, 4, 5, 6, 7, 8, 9, 10, 1]]))
How do I keep the for loop running even after the first false is returned from the areEqual() function?
A side note: I understand that this could probably use some refactoring... like, I was working on this with someone earlier and they mentioned how I can simply shift the array by writing a helper function like shiftArray(arr){return arr.push(arr.pop())} but I don't get how that implementation would work considering that all that's returned is the value that was taken out of the array, not the new shifted array.
You may be doing too much work.
Say you have an array A of n integers, zero indexed.
Parse the array from index 0 to n mod n (so 0 twice). Count the number of pairs where the latter integer is less than the former, and store the first index where this happens.
If the count is 1 and the location is k (so A[k] < A[k-1]), then a cyclic shift of either -k or n-k will convert A to a sorted array. If the count is greater than 1 then there's no solution.
E.g., [4,5,0,1,2,3] -- we see k=2 is the only index which has a value below its predecessor, and a cyclic shift of -2 or 4 forms [0,1,2,3,4,5] which is sorted.

if Input: 8-e Expected Output: 2|4|6|8

Question 2: The input consist of a string, "o" represents odd number, "e" represents even number to be printed
Example 1.
Input: 8-e
Expected Output: 2|4|6|8
Example 2.
Input: 6-o
Expected Output: 1|3|5
Example 3.
Input: 1-o
Expected Output: 1
if have tried with for loop, but I'am a beginner so I'am confused with(-e)
const evenOdd = (number) => {
let evenvalue = [];
let oddValue=[];
for(let i =0; i<=number; i++){
if(number%i==0)
evenvalue.push(i);
console.log(evenvalue);
}if(number%i!=0){
oddValue.push(i);
console.log(oddValue);
}
};
evenOdd(9);
You could take a while statement and get a start value of one plus an offset of one if the wanted type is even. Then iterate and add the value to the result set until the value is greater than the maximum value.
function fn(request) {
var [max, type] = request.split('-'),
i = 1 + (type === 'e'),
result = [];
while (i <= max) {
result.push(i);
i += 2;
}
return result;
}
console.log(...fn('8-e'));
console.log(...fn('6-o'));
console.log(...fn('1-o'));
You will need to extract the letter and the number from you string first. One easy way to do that :
const evenOdd = (s) => {
let odd = s.length-1 ==='o';
let number = Number(s.substring(0, s.length-2));
let evenvalue = [];
...
if(odd){...} else {...}
};
You could also use split() or if the pattern was more complicated, a Regex.
You can split on - and add based on type add values upto the number
Split the given input by -, first value represents max number and second represents it's type
Check the type if it is even add the even values start from 2 and upto to the max number else start from 1, and join them with | in the end
let func = (input) => {
let [num, type] = input.split('-')
let arr = []
let i = 1 + (type === 'e')
while (i <= num) {
arr.push(i)
i += 2
}
return arr.join('|')
}
console.log(func('8-e'))
console.log(func('1-o'))
console.log(func('6-o'))
Basically, don't supply a number to the function, supply a string and then parse the string. That is, don't try and give the function 9-e, give it '9-e'.
Get the parts of the input by splitting on -.
Turn the number into a number.
Give 0 for even, 1 for odd (x % 2 is 0 for even number, 1 for odd).
Build the results.
function listNumbers(constraint)
{
const parts = constraint.split('-');
const number = Number(parts[0]);
const numberType = parts[1] === 'e' ? 0:1;
let result = [];
for(let i = 1; i <= number; i++)
{
if(i%2 === numberType)
{
result.push(i);
}
}
return result;
}
console.log(listNumbers('8-e'));
Or if you want make the code look clever:
function listNumbers(constraint)
{
const parts = constraint.split('-');
const number = Number(parts[0]);
const numberType = parts[1] === 'e' ? 0:1;
return Array.from(Array(number), (x,i) => i + 1 ).filter(x => x%2 == numberType);
}
console.log(listNumbers('8-e'));

Why does passing in a number as a string into an array cause the wrong result?

I have built a function that allows you to pass through an array and it successfully returns the second highest and second lowest numbers. However, I'm new to error handling and don't understand why this fails:
getNos([5,"5",8]);
It works correctly when passing in getNos([5,5,8]); or passing arrays like getNos(["5",8]);.
Can someone explain what's happening here and how to fix it? Thanks for any help here - the function code is below:
function getNos(arr){
if (!Array.isArray(arr) || arr.length == 0 || arr.length == 1 || (arr.every(c => !isNaN(c)) == false)) {
throw 'Invalid Input';
} else {
var result;
var uniqueVals = Array.from(new Set(arr));
var highest = highestVal(arr);
var lowest = lowestVal(arr);
if (uniqueVals.length == 1) {
result = arr[0] + " " + arr[0];
} else if (arr.length == 2 || uniqueVals.length == 2) {
result = highest + " " + lowest;
} else {
arr = arr.filter(item => ((item !== highest) && (item !== lowest)));
var secondHighest = highestVal(arr);
var secondLowest = lowestVal(arr);
if (arr.length == 1) {
arr = arr.slice(arr.indexOf(secondHighest));
result = highestVal(arr);
} else {
result = secondLowest + " " + secondHighest;
}
}
return result;
}
function highestVal(a) { return a.reduce((a, b) => a > b ? a : b ) };
function lowestVal(a) { return a.reduce((a, b) => a < b ? a : b ) };
}
Follow carefully the logic var uniqueVals = Array.from(new Set(arr)). What will this line return when you have arrays such as [5,"5",8] vs [5,5,8] vs ["5", 8]?
A Set stores unique value of a type. "5" is of type string whereas 5 is of type number. The highestVal and lowestVal functions can compare "5" and 8, no problem, but since an array could include either a string or number for either 5 or 8 as well, then you will get funny values being returned.
To fix this, before passing arr to the Set, you need to convert all values to a single type, preferably number.
let numberArr = arr.map(el=>+el) is one way of doing that, but you may want better data validation than that.
Simple fix would be map the values to numbers before creating the set to avoid having the same numeric values as both string and number in the set
Change
var uniqueVals = Array.from(new Set(arr));
To
var uniqueVals = Array.from(new Set(arr.map(Number)));
The function does not fail in the sense that it throws an error. For these types of questions please add an example of "expected results".
When you compare strings and numbers in JavaScript, you are relying on implicit coercion to take care of the comparison. In this case it won't throw and error and break anything, it is fine as JavaScript will convert your string to a number and compare (unless its a strict equality === which checks type as well).
Should the result be based off what was passed in? Or after the input has been filtered for numbers only. Or if the input can be converted to valid numbers?
In the case of filter for valid numbers. Filter the input as follows...
arr = arr.filter(data => typeof data === 'number')
In the case of converting values to a number and removing those that cannot be converted...
arr = arr.reduce(((acc, el) => {
const num = Number(el);
if (!Number.isNaN(num)) acc.push(num);
return acc;
}), []);

Generate list of items with 0 prefix using padStart

I implemented the way to generate a list of items with iterable counts with prefix 0. What is the best way to generate such kind of list?
Current behaviour:
const generateList = (length, n, i) => {
let b = n+i
return b.toString().padStart(length.toString().length + n.toString.length, 0)
}
Array(10).fill(null).map((x, i) => generateList(10,2, i))
Output result:
["002", "003", "004", "005", "006", "007", "008", "009", "010", "011"]
Do u have any idea to make it another way?
You could determine the number of characters needed at the start and used the predetermined value to format the output for the array.
function createList(startValue, endValue) {
let
// The minimum output length, for a single digit number, is 2 chars.
outputLength = 2,
testValue = 10,
// Create an empty array which has as many items as numbers we need to
// generate for the output. Add 1 to the end value as this is to be
// inclusive of the range to create. If the +1 is not done the resulting
// array is 1 item too small.
emptyArray = Array(endValue - startValue + 1);
// As long as test value is less than the end value, keep increasing the
// output size by 1 and continue to the next multiple of 10.
while (testValue <= endValue) {
outputLength++;
testValue = testValue * 10;
}
// Create a new array, with the same length as the empty array created
// earlier. For each position place a padded number into the output array.
return Array.from(emptyArray, (currentValue, index) => {
// Pad the current value to the determined max length.
return (startValue + index).toString().padStart(outputLength, '0');
});
}
function createListWithLength(length, startValue = 0) {
return createList(startValue, startValue + length);
}
console.log(createList(2,10));
console.log(createListWithLength(30));
console.log(createListWithLength(10, 995));
Have a look at generators:
function* range(from, to) {
for (var i=from; i<to; i++)
yield i;
}
function* paddedRange(from, to) {
const length = (to-1).toString(10) + 1 /* at least one pad */;
for (const i of range(from, to))
yield i.padStart(length, '0');
}
console.log(Array.from(paddedRange(2, 12)));
You can also inline the loop from range into paddedRange, or you can make it return an array directly:
function paddedRange(from, to) {
const length = (to-1).toString(10) + 1 /* at least one pad */;
return Array.from(range(from, to), i => i.padStart(length, '0'));
}
console.log(paddedRange(2, 12));
The main simplification is that you should compute the padding length only once and give it a denotative name, instead of computing it for every number again. Also ranges are usually given by their lower and upper end instead of their begin and a length, but you can easily switch back if you need the latter for some reason.
Not sure, but maybe something like this
const generateList = length => Array(length).fill('0').map((item, index) => item + index);
console.log(generateList(20));

Check if a string is sorted in javascript

please i want to check if this string is sorted?
var myBucket = "1D2D1W2W1M2M3M4M5M6M9M1Y18M2Y30M3Y4Y5Y6Y8Y10Y15Y20Y25Y30Y1D2D1W2W1M2M3M4M5M6M9M1Y18M2Y30M3Y4Y5Y6Y8Y10Y15Y20Y25Y30Y";
1D=One Day 2D=2 Day ...
1W=1 Week
1M=1 Months 18M=18 Months
1Y=1 years
like 1D<2D<1W<3W<1M<10M<1Y<18M<2Y ...
How can i check this?
Thank you in advance.
I suggest to match a number and the length indicator. Then loop over with Array#every and split the part into number and length indicator. With a hash table for the length, you could calculate the length and test it with the last value before.
If greater, then proceed, else leave the loop and get false.
If the loop iterates over all elements, and the callback returns true, then it return true.
var myBucket = '1D2D1W2W1M2M3M4M5M6M9M1Y18M2Y30M3Y4Y5Y6Y8Y10Y15Y20Y25Y30Y1D2D1W2W1M2M3M4M5M6M9M1Y18M2Y30M3Y4Y5Y6Y8Y10Y15Y20Y25Y30Y',
values = { D: 1, W: 7, M: 30, Y: 365 },
result = myBucket.match(/\d+[DWMY]/g).every(function (a, i) {
var p = a.split(/(?=[DWMY])/),
value = p[0] * (values[p[1]] || 0);
if (value > this.last) {
this.last = value;
return true;
}
}, { last: -Infinity });
console.log(result);

Categories