How do I pass a variable into a JS while loop? - javascript

I want to recursively sum an integer: to split an integer into an array and then sum the individual items until I am left with a single integer array.
This is my logic:
Take an integer (n) and split it into an array.
Sum all the individual numbers.
Is the number greater than 9?
YES: Repeat steps 1 and 2
NO: Return the number
function digital_root(n) {
let digits = (""+n).split("").map(Number);
while (digits.length > 1) {
let result = digits.reduce((sum, int) => sum + int);
let digits = (""+result).split("").map(Number);
}
return digits;
};
This is the error code my Node.js chucks at me (at line 4 in the example code above):
ReferenceError: digits is not defined
at digital_root (repl:6:18)
I'm assuming that the variable digits is accessible inside the scope of the while loop, but obviously, I seem to be wrong? Could someone shed some insight here for me, please?
EDIT: Thank you everyone for your help! I've solved the issue.
For your curiosity, this is the mathematical form underlying my algorithm:
http://mathworld.wolfram.com/DigitalRoot.html
It could also have been solved in one line:
function digital_root(n) {
return (n - 1) % 9 + 1;
}

The inner let for digits (line 5) should be removed
function digital_root(n) {
let digits = (""+n).split("").map(Number);
while (digits.length > 1) {
let result = digits.reduce((sum, int) => sum + int);
digits = (""+result).split("").map(Number);
}
return digits;
}

Issue is let keyword, as let has block level scope, "digits" is not defined at the start of the while loop
Removing let for digits in while loop
function digital_root(n) {
let digits = (""+n).split("").map(Number);
while (digits.length > 1) {
let result = digits.reduce((sum, int) => sum + int);
digits = (""+result).split("").map(Number);
}
return digits;
}
console.log(digital_root(47))

Don't set digits in that manner, the digits inside of the loop should not have let in front of it because you have already defined digits outside the loop.
This will give you the result you expect:
digital_root = n => (Array.from(`${n}`)).reduce((sum, val) => sum + ~~val, 0);
console.log(digital_root(12345));
Hope this helps,

Related

How to round down integer to all zeros behind first number

For example, I need to round number 6588 => 6000 , 1285000 => 1000000
I can't find any Math.ceil , Math.floor methods that can achieve this.
You can divide by the highest power of ten, floor it, then multiply back by the highest power of ten. Some other answers are manipulating string, but IMO this is the simplest and easiest to read code. Like this:
function roundDown(num) {
let powerOfTen = num.toString().length - 1;
num /= (10**powerOfTen);
return Math.floor(num) * (10**powerOfTen);
}
console.log(roundDown(6588)) // => 6000
console.log(roundDown(1285000)) // => 1000000
This is roughly the same procedure that Math.floor() uses, as described in this MDN article;
another variant is just work on string level, instead of numbers to avoid any floating point problems
function roundToFirst(n) {
return (''+n).split('').map((c, i) => i > 0 ? '0' : c).join('');
}
console.log(roundToFirst(6588)); // 6000
console.log(roundToFirst(1285000)); // 1000000
You can convert your number to a string and simply append zeros to match the number's length.
const roundDown = (num) => {
num = num.toString();
return (num[0] + new Array(num.length).join('0'));
}
console.log(roundDown(6588))
console.log(roundDown(0))
A short and easy way is to take the first digit and padEnd the rest
const roundDown = num => {
num = String(num)
return +num[0].padEnd(num.length, "0")
}
console.log(roundDown(6588))
console.log(roundDown(1285000))
References
padEnd

How to remove the numbers that already occur with their digits reversed

I need a function that will take an array of numbers, and which will return an array that only retains the numbers that are unique in their digit sequence, i.e. that only occur once even if you would reverse their digits.
This is my code so far:
var a=[5,8,3,8,3,7,5,12,21];
console.log(a);
let output=[...new Set([...a])] // it removes the repeated data...
console.log(output);
This works for the numbers 3, 8 and 5, whose duplicates are removed, but the value 21 should also be removed, because there is already 12, which is 21 with the digits in reversed order.
How can I achieve that?
The expected output for the above example is:
[5,8,3,7,12]
My code returns:
[5,8,3,7,12,21]
You need (of course) to include the logic of reversing digits in a number.
I will assume that when the rightmost digit of a number is 0, that the reversal of that number is not defined. So the reversal of 19 is 91, but the reversal of 190 is not 91, but undefined (or NaN).
First define a function for that reversal of digits, and then use the idea of building a set:
function reverseDigits(num) {
// A Number should not have 0 as first digit
// unless it is 0
if (num && num % 10 == 0) return NaN;
return +[...String(num)].reverse().join("");
}
function specialUnique(a) {
const set = new Set;
for (const value of a) {
if (!set.has(value) && !set.has(reverseDigits(value))) {
set.add(value);
}
}
return [...set];
}
// Example input
const a = [5,8,3,8,3,7,5,12,21];
const output = specialUnique(a);
console.log(output);
You can use the filter.
let valueToRemove = 21;
output = output.filter((item) => item !== valueToRemove);

How to implement an algorithm to detect if a number has 2 consecutive digits?

I want to create a function that returns true if a number has consecutive digits or not,
example:
if the input is 11, it will return true
if the input is 21 it will return false
if the input is 323 it will return false because even though we have 3 repeated, they are not consecutive
My solution right now is to transform the number into an array and loop through the number one by one, if the next number is equal to the current number then we just return true. But this has a complexity time of O(n) and I was wondering if anyone can come with a better solution.
Thank you
There is an arguably better solution where you don't need to convert the number into a string or array of numbers/character. It works as follows:
Initialize a variable curr to -1.
Run a loop while num > 0 and do the following:
next_curr = num % 10
if next_curr == curr: return true
curr = next_curr
num = num / 10 (integer division)
If the loop completes, return false.
This is a one pass O(log n) time complexity algorithm where n is the input number. The space complexity is O(1)
Note that while your algorithm was also O(log n) time complexity, it did 2 passes, and had a space complexity of O(log n) too.
I haven't written JS for some time now, but here's a possible implementation of the above algorithm in JS:
function sameAdjacentDigits(num) {
// to deal with negative numbers and
// avoid potential problems when using Math.floor later
num = Math.abs(num)
let curr = -1
while (num > 0) {
const nextCurr = num % 10
if (nextCurr == curr) return true
curr = nextCurr
num = Math.floor(num / 10)
}
return false
}
Use some regex, and then check what was found via the matcher
numbers_match = /(00|11|22|33|44|55|66|77|88|99)/;
numbers_match.match("11")
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/match
Easiest way to execute this is by using regex. Not sure what would be effectiveness of algorithm, but solution could be
/(\d)\1/
Inspired from #Tschallacka's answer:
let numbers = [11,21,323];
let result = numbers.map(n=>{
let test = n.toString().match(/(00|11|22|33|44|55|66|77|88|99)/);
return test != null;
})
console.log(result);

Sum Strings as Numbers

I am trying to solve a kata that seems to be simple on codewars but i seem to not be getting it right.
The instruction for this is as simple as below
Given the string representations of two integers, return the string representation of the sum of those integers.
For example:
sumStrings('1','2') // => '3'
A string representation of an integer will contain no characters besides the ten numerals "0" to "9".
And this is what i have tried
function sumStrings(a,b) {
return ((+a) + (+b)).toString();
}
But the results solves all except two and these are the errors i get
sumStrings('712569312664357328695151392', '8100824045303269669937') - Expected: '712577413488402631964821329', instead got: '7.125774134884027e+26'
sumStrings('50095301248058391139327916261', '81055900096023504197206408605') - Expected: '131151201344081895336534324866', instead got: '1.3115120134408189e+29'
I don't seem to understand where the issues is from. Any help would help thanks.
The value you entered is bigger than the int type max value. You can try changing your code to:
function sumStrings(a,b) {
return ((BigInt(a)) + BigInt(b)).toString();
}
This way it should return the right value
You could pop the digits and collect with a carry over for the next digit.
function add(a, b) {
var aa = Array.from(a, Number),
bb = Array.from(b, Number),
result = [],
carry = 0,
i = Math.max(a.length, b.length);
while (i--) {
carry += (aa.pop() || 0) + (bb.pop() || 0);
result.unshift(carry % 10);
carry = Math.floor(carry / 10);
}
while (carry) {
result.unshift(carry % 10);
carry = Math.floor(carry / 10);
}
return result.join('');
}
console.log(add('712569312664357328695151392', '8100824045303269669937'));
console.log(add('50095301248058391139327916261', '81055900096023504197206408605'));
The problem is that regular javascript integers are not having enough space to store that much big number, So it uses the exponential notation to not lose its precision
what you can do is split each number into parts and add them separately,
one such example is here SO answer
My solution is:
function sumStrings(a,b) {
return BigInt(a) + BigInt(b) + ''
}
Converting from a string to a number or vice versa is not perfect in any language, they will be off by some digits. This doesn't seem to affect small numbers, but it affects big numbers a lot.
The function could go like this.
function sumStrings(a, b) {
return (BigInt(a) + BigInt(b)).toString() // or parseInt for both
}
However, it's still not perfect since if we try to do:
console.log((4213213124214211215421314213.0 + 124214321214213434213124211.0) === sumStrings('4213213124214211215421314213', '124214321214213434213124211'))
The output would be false.

How to get a term before a character?

How to get the number before 'x'?
I tried using .split('x')[0] but it grabs everything before 'x'.
123x // Gives 123
123y+123x - // Gives 123
123x+123x - // Gives 246
I've tested a function which uses regex that I think will work. I've included the results, an explanation of how the function works, and then a commented version of the function.
Note, this doesn't handle any algebra more complex than adding and subtracting simple terms. I would refer to https://newton.now.sh/ for that, it's an API which can handle simplification (I am not affiliated).
Results:
console.log(coefficient("-x+23x")); // 22
console.log(coefficient("123y+123x")); // 123
// replaces spaces
console.log(coefficient("x + 123x")); // 124
console.log(coefficient("-x - 123x")); // -124
console.log(coefficient("1234x-23x")); // 1211
// doesn't account for other letters
console.log(coefficient("-23yx")); // 1
Explanation:
First the function removes spaces. Then it uses a regex, which finds any sequence of numbers that are followed by an 'x'. If there's a +/- in front, the regex keeps that. The function loops through these sequences of numbers, and adds them to a total. If there's an 'x' that does not have numbers with it, its coefficient is assumed as -1 or 1.
Commented Code:
function coefficient(str) {
// remove spaces
str = str.replace(/\s/g, '');
// all powerful regex
var regexp = /(\+|-)?[0-9]*x/g
// total
sum = 0;
// find the occurrences of x
var found = true;
while (found) {
match = regexp.exec(str);
if (match == null) {
found = false;
} else {
// treated as +/- 1 if no proceeding number
if (isNaN(parseInt(match[0]))) {
if (match[0].charAt(0) == "-") {
sum--;
} else {
sum++;
}
// parse the proceeding number
} else {
sum += parseInt(match[0]);
}
}
}
return sum;
}
I don't know if there is sufficient cleverness in ECMAScript regular expressions to do look behind, but you can do it with match and post processing to remove the "x".
If the intention is to sum the terms, then a further operation with reduce is required. Trimming the x could be combined with reduce so that map isn't required.
console.log(
'123x+123x'.match(/\d+x/ig).map(function(v){
return v.slice(0,-1)
}).reduce(function(sum, v){return sum + +v},0)
);
console.log(match('123x+123y+456x', 'x'))
console.log(match('123x+123y+456x', 'y'))
function match(str, x) {
return str.match(new RegExp('\\d+' + x, 'g')).reduce((cur, p) => {
return cur + parseInt(p.substr(0, p.length - x.length))
}, 0)
}

Categories

Resources