Sum a negative number's digits - javascript

'Write a function named sumDigits which takes a number as input and
returns the sum of each of the number's decimal
digits.'
How can I sum the digits with the first digit being negative?
For example: sumDigits(-32); // -3 + 2 = -1;
I was able to solve it partially.
function sumDigits(number) {
return Math.abs(number).toString().split("").reduce(function(a, b) {
return parseInt(a) + parseInt(b);
}, 0);
}
console.log( sumDigits(-32) );

Simple math and recursion make short work of this problem.
Recall that when you divide a number by 10, the remainder is its rightmost decimal digit and the integer part of the quotient is the number formed by the remaining digits. In other words:
let n = 5678;
console.log(n % 10); // => 8
console.log(Math.floor(n / 10)); // => 567
With this in mind, summing a number's digits is a straightforward recursive procedure:
Procedure(n)
Divide n by 10.
Set digit to the remainder.
Set n to the integer part of the quotient.
If n = 0, return digit.
Otherwise, return digit + Procedure(n)
Keeping the sign for the leftmost digit adds a small amount of complexity, but not much. Here's how it looks in JavaScript:
function digitSum(n, sign=1) {
if (n < 0) {
sign = -1; // Save the sign
n = Math.abs(n);
}
const digit = n % 10; // Remainder of |n÷10|
n = Math.floor(n / 10); // Integer part of |n÷10|
if (n === 0) {
return sign * digit; // No digits left, return final digit with sign
}
return digit + digitSum(n, sign); // Add digit to sum of remaining digits
}
console.log(digitSum(32)); // => 5
console.log(digitSum(-32)); // => -1

Here is a way to do it with Array.prototype.reduce().
Stringify the input and split it on each character.
Iterate over the characters with reduce.
Initialize the accumulator with a sum of 0 and a multiplier of 1.
If the first character is a -, set the multiplier to -1
For the subsequent characters, multiply the digit with the multiplier and add it to the sum. Then set the multiplier back to 1 so the next digits will only be multiplied by 1.
const sumDigits = x => [...`${x}`].reduce(({ sum, mult }, x, i) => {
return i === 0 && x === '-' ? { sum: 0, mult: -1 } : { sum: sum + mult * x, mult: 1 };
}, { sum: 0, mult: 1 }).sum;
console.log(sumDigits(-32)); // -1
console.log(sumDigits(32)); // 5
console.log(sumDigits(5555)); // 20

Here's a way you can do it without String conversion -
const sumDigits = (n = 0) =>
n < 0
? n > -10
? n
: (-n % 10) + sumDigits (n / 10 >> 0)
: n < 10
? n
: (n % 10) + sumDigits (n / 10 >> 0)
console.log(sumDigits(-321))
// (-3 + 2 + 1)
// => 0
console.log(sumDigits(321))
// (3 + 2 + 1)
// => 6
The same answer using imperative style -
const sumDigits = (n = 0) =>
{ if (n < 0)
if (n > -10)
return n
else
return (-n % 10) + sumDigits (n / 10 >> 0)
else
if (n < 10)
return n
else
return (n % 10) + sumDigits (n / 10 >> 0)
}
console.log(sumDigits(-321))
// (-3 + 2 + 1)
// => 0
console.log(sumDigits(321))
// (3 + 2 + 1)
// => 6

An approach that does not require converting to a string adapted from another answer by #NinaScholz to a closely related question (for those that are bitwise shift operator challenged).
Converts the number to its absolute value, loops with modulus operator to sum the remainder after dividing by 10 until a ones value remains, and then subtracts the leftmost digit if the original number was negative.
const sumDigits = (n) => {
const negative = !!(n < 0);
let sum = 0;
let num = negative ? Math.abs(n) : n;
while (num) {
if (negative && num <= 10) {
sum -= num % 10;
} else {
sum += num % 10;
}
num = Math.floor(num / 10);
}
return sum;
};
console.log(sumDigits(-32));
// -1

You could take a different method for separating the digits and keep the first one with a possible sign.
'-32'.match(/-?\d/g)
returns
['-3', '2']
function sumDigits(number) {
return number.toString().match(/-?\d/g).reduce(function(a, b) {
return a + +b;
}, 0);
}
console.log(sumDigits(-32));

First, "decimal digits" means only the characters to the right of the decimal point. Converting the number to a string sets you up as JavaScript strings are arrays of characters. So, then it's just a matter of splitting out the decimal digits then summing them by iterating that array, then converting back to a number type.
//'Write a function named sumDigits which takes a number as input and returns the sum of each of the number's decimal digits.'
var a = 10.12345;
var b = -1012345;
function sumDigits(x){
var result = 0;
x = x.toString();
x = x.split('.')[1];
if (x == null){
//there's not decimal digits to sum!
return "there's not decimal digits to sum!"
}
for (var i = 0; i < x.length; i++) {
if (digit >= 0 && digit <= 9) { //just in case, probably unnecessary
var digit = Number(x[i]);
result = result + digit;
}
}
//if you care about negative uncomment this
//if(x[0] === "-"){
// result = result * -1;
//}
return result;
}
console.log(sumDigits(a));
console.log(sumDigits(b));

// try this to get the sum of negatives:
const sumOfNegative = (numbers) => {
let sum = 0;
numbers.forEach((number) => {
if (number < 0) {
sum += number;
}
});
return sum;
};

Related

how to find two max numbers ( negative and positive ) in array?

I'm looking for best solution to solve this problem
Problem:
Create a function named ArrayChallenge (Javascript) which accepts a single argument "arr" which is an array of numbers. This function will return the string true if any two numbers can be multiplied so that the answer is greater than double the sum of all the elements in the array. If not, return the string false.
For example:
if the argument "arr" is [2, 5, 6, -6, 16, 2, 3, 6, 5, 3] then the sum of all these elements is 42, and doubling it is 84. There are two elements in "arr", 16 * 6 = 96 where 96 is greater than 84, so your program should return the string true. An example of an "arr" that should return false is [1, 2, 4] since double its sum (14) is larger than multiplying its two largest elements (4 * 2 = 8).
my solution was
function ArrayChallenge(arr) {
if (arr.length < 2) return 'false'
let maxNeg = 0
let neg = 0
let pos = 0
let maxPos = 0
const sum = arr.reduce((total, num) => {
if (num < 0) {
if (num < neg) maxNeg = num
else neg = num
} else {
if (num >= maxPos) {
pos = maxPos
maxPos = num
} else if (num > pos) pos = num
}
return total + num
}, 0)
if (maxPos * pos > sum * 2 || maxNeg * neg > sum * 2) return 'true'
else return 'false'
}
https://codepen.io/hamodey85/pen/ExmrdgM
For this problem you need to understand the fact that if the highest possible product of the 2 numbers in the array are not greater than the twice sum of the array then there are no possible pairs available.
Steps to solve the problem
step 1
precompute the sum of the array.(can be easily done using for loop or reduce function)
step 2
get the 2 maximum values from the array(depending on allowed complexity you can either sort the array and get it i.e.O(nlogn) or traverse the array twice i.e.O(2n) which is better.
step 3
compare product of the 2 maximum and precomputed sum and return true if product is greater than the precomputed sum
Sorting Apprach
function ArrayChallenge(arr){
var precomputedSum = arr.reduce((a,c) => a+c,0); //Step 1
var sortedArray = arr.sort(function(a, b){return b-a});// Step 2
var product = sortedArray[0] * sortedArray[1];//part of step 2
return product > 2*precomputedSum ;
}
looping approach
function ArrayChallenge(arr){
var precomputedSum = arr.reduce((a,c) => a+c,0); //Step 1
int firstMax = -2147483648;// Step 2
for(int i=0;i<arr.length;i++){
if(arr[i]>firstMax)firstMax=arr[i];//step 2
}
int secondMax = -2147483648;// Step 2
for(int i=0;i<arr.length;i++){
if(arr[i]>secondMax && arr[i]!=firstMax)secondMax=arr[i];//step 2
}
var product = firstMax * secondMax;//part of step 2
return product > 2*precomputedSum ;
}
so I tried to solve it in several way but I found this better solution so far
function ArrayChallenge(arr) {
if (arr.length < 2) return 'false'
let maxNeg = 0
let neg = 0
let pos = 0
let maxPos = 0
const sum = arr.reduce((total, num) => {
if (num < 0) {
if (num < neg) maxNeg = num
else neg = num
} else {
if (num >= maxPos) {
pos = maxPos
maxPos = num
} else if (num > pos) pos = num
}
return total + num
}, 0)
if (maxPos * pos > sum * 2 || maxNeg * neg > sum * 2) return 'true'
else return 'false'
}

Difficulty in constructing Luhn's algorithm

I want to construct Luhn's algorithm which is usually used to validate credit card numbers. Luhn's algorithm works like this:
Isolate every digit, starting from the right moving left, doubling every second one. If the doubled value is greater than 9, subtract 9 from it.
Sum all the transformed digits.
The original number valid according to Luhn's algorithm if and only if the sum ends in a 0.
function isValid(number) {
return LuhnDigitSum(number) % 10 === 0;
}
function LuhnDigitSum(number) {
let sum = 0;
let num_str = number.toString();
let reversed_num = num_str.split("").reverse().join("");
for (let i = 0; i < reversed_num.length; i++) {
let digit = parseInt(reversed_num[i]);
if (i % 2 !== 0 && (digit * 2) <= 9) {
digit = digit * 2;
sum += digit;
}
if (i % 2 !== 0 && (digit * 2) > 9) {
digit = (digit * 2) - 9;
sum += digit;
}
if (i % 2 === 0) {
sum += digit;
}
}
return sum;
}
When i run the code, the card numbers appeared to be invalid when they are supposed to be valid, and adding to that, the sum value were incorrect.
Your help is much appreciated. Thanks!!

Extracting middle of string - JavaScript

I am trying to write an algorithm for this in JavaScript but I am getting a str.length is not a function...
function extractMiddle(str) {
var position;
var length;
if(str.length() % 2 == 1) {
position = str.length() / 2;
length = 1;
} else {
position = str.length() / 2 - 1;
length = 2;
}
result = str.substring(position, position + length)
}
extractMiddle("handbananna");
Because string length is not a function, it's a property.
function extractMiddle(str) {
var position;
var length;
if(str.length % 2 == 1) {
position = str.length / 2;
length = 1;
} else {
position = str.length / 2 - 1;
length = 2;
}
return str.substring(position, position + length)
}
console.log(extractMiddle("handbananna"));
Here is an another way to do this:
function extractMiddle(str) {
return str.substr(Math.ceil(str.length / 2 - 1), str.length % 2 === 0 ? 2 : 1);
}
// the most amazing
const getMiddle = s => s.substr(s.length - 1 >>> 1, (~s.length & 1) + 1);
// should return "dd"
console.log(getMiddle('middle'))
// >>> is an unsigned right shift bitwise operator. It's equivalent to division by 2, with truncation, as long as the length of the string does not exceed the size of an integer in Javascript.
// About the ~ operator, let's rather start with the expression n & 1. This will tell you whether an integer n is odd (it's similar to a logical and, but comparing all of the bits of two numbers). The expression returns 1 if an integer is odd. It returns 0 if an integer is even.
// If n & 1 is even, the expression returns 0.
// If n & 1 is odd, the expression returns 1.
// ~n & 1 inverts those two results, providing 0 if the length of the string is odd, and 1 if the length of the sting is even. The ~ operator inverts all of the bits in an integer, so 0 would become -1, 1 would become -2, and so on (the leading bit is always the sign).
// Then you add one, and you get 0+1 (1) characters if the length of the string is odd, or 1+1 (2) characters if the length of the string is even.
#author by jacobb
the link of the source is: https://codepen.io/jacobwarduk/pen/yJpAmK
That seemed to fix it!
function extractMiddle(str) {
var position;
var length;
if(str.length % 2 == 1) {
position = str.length / 2;
length = 1;
} else {
position = str.length / 2 - 1;
length = 2;
}
result = str.substring(position, position + length)
console.log(result);
}
https://jsfiddle.net/sd4z711y/
The first 'if' statement is to get the odd number while the 'else if' is to get the even number.
function getMiddle(s)
{
if (s.length % 2 == 1) {
return s.substring((s.length / 2)+1, (s.length / 2))
} else if (s.length % 2 == 0) {
return s.substring((s.length / 2)-1, (s.length / 2)+1)
}
}
console.log(getMiddle("handers"));
console.log(getMiddle("test"));
Here is my solution :-
function pri(word) {
if (!word) return 'word should have atleast one character';
let w = [...word].reduce((acc, val) => (val == ' ' ? acc : (acc += val)));
let res = '';
let length = word.length;
let avg = length / 2;
let temp = avg % 2;
if (temp == 0) {
res += word.charAt(avg - 1) + word.charAt(avg);
} else {
res += word.charAt(avg);
}
return res;
}
console.log(pri("Lime")); // even letter
console.log(pri("Apple")); // odd letter
console.log(pri("Apple is Fruit")); // String sequence with space
console.log(pri("")); // empty string
here is my solution
function getMiddle(s){
let middle = Math.floor(s.length/2);
return s.length % 2 === 0
? s.slice(middle-1, middle+1)
: s.slice(middle, middle+1);
}
function extractMiddle(s) {
return s.substr(Math.ceil(s.length / 2 - 1), s.length % 2 === 0 ? 2 : 1);
}
extractMiddle("handbananna");
str.length is a property. Just get rid of the parentheses. Example:
if (str.length == 44) {
length is a property of string, not a function. Do this instead:
str.length % 2 === 1
Also, use I suggest favoring === over ==
Since length is not a function, there is no need to use ().
function getMiddle(str) {
if(str.length % 2 === 0 ) {
return str.substr(str.length/2-1, 2);
} else {
return str.charAt(Math.floor(str.length/2));
}
}
console.log(getMiddle("middbkbcdle"));

Change base of a number in JavaScript using a given digits array

I was required to make a method to convert integer from base ten to some another base in JavaScript, and it should also support providing your custom digits array. For example,
toBase(10, 2 ["A","B"])// returns 'BABA'
and if digits array is not provided, it should work as JavaScript 'toString' method
var a = 10;
a.toString(2);//returns '1010'
I have wrote a function to convert an integer to another base from base 10 number, with an option of providing digits array -
function toBase(number, radix, digits)
{
radix = radix || 10;
digits = digits || "0123456789abcdefghijklmnopqrstuvwxyz".split("").slice(0, radix)
if (radix > digits.length) {
var msg = "Not enough digits to represent the number '" + number + "' in base " + radix;
throw Error(msg);
}
if (number === 0) return digits[0];
var a = []
while (number) {
a.splice(0, 0, digits[number % radix])
number = parseInt(number / radix);
}
return a.join("");
}
This function works fine for me, but I want to know if is there any better way to do it? Thanks.
You can just use the native toString method and then replace the output with those from the digits array:
function toBase(number, radix, digits) {
if (digits && digits.length >= radix)
return number.toString(radix).replace(/./g, function(d) {
return digits[ parseInt(d, radix) ];
});
else
return number.toString(radix);
}
A method that might be slightly faster than the way you have is to bit shift. This works most easily when radix is a power of 2, here is an example
function toBase(x, radix, A) {
var r = 1, i = 0, s = '';
radix || (radix = 10); // case no radix
A || (A = '0123456789abcdefghijklmnopqrstuvwxyz'.split('')); // case no alphabet
if (A.length < radix) throw new RangeError('alphabet smaller than radix');
if (radix < 2) throw new RangeError('radix argument must be at least 2');
if (radix < 37) return useBergisMethod(x, radix, A); // this is arguably one of the fastest ways as it uses native `.toString`
if (x === 0) return A[0]; // short circuit 0
// test if radix is a power of 2
while (radix > r) {
r = r * 2;
i = i + 1;
}
if (r === radix) { // radix = 2 ^ i; fast method
r = r - 1; // Math.pow(2, i) - 1;
while (x > 0) {
s = A[x & r] + s;
x >>= i; // shift binary
}
return s; // done
}
return methodInOriginalQuestion(x, radix, A); // else not a power of 2, slower method
}
/*
toBase(74651278, 64, '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyzáé');
"4SnQE"
// check reverse
var i, j = 0, s = '4SnQE', a = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyzáé';
for (i = 0; i < s.length; ++i) j *= 64, j += a.indexOf(s[i]);
j; // 74651278, correct
*/

JavaScript Function: Generate a random integer within specified range AND digit limit

I need a function that generates a completely random integer (very important) within a user specified number range (between -9999 to 9999) and a user specified digit limit (between 1 and 4 digits).
Example 1: If the user wants a number between -9999 and 9999 that's 4 digits, the following numbers would be eligible choices -9999 to -1000 and 1000 to 9999.
Example 2: If the user wants a number between 25 and 200 that's 2 OR 3 digits, the following numbers would be eligible choices 25 to 200.
I wrote a function that works but I am not sure if it's the best solution? There's duplicate code and I don't think it's completely random?
// Generates a random integer
// Number range
// Min (-9999-9999)
// Max (-9999-9999)
// Digit limit
// Min (1-4)
// Max (1-4)
function generateRandomInteger(minNumber, maxNumber, minDigits, maxDigits) {
// Generate a random integer in the number range
var num = Math.floor(Math.random() * (maxNumber - minNumber)) + minNumber;
// Find number of digits
var n = num.toString();
n = n.length;
// If number is negative subtract 1 from length because of "-" sign
if (num < 0) {
n--;
}
// End: find number of digits
while ((n > maxDigits) || (n < minDigits)) {
// Generate a random integer in the number range
num = Math.floor(Math.random() * (maxNumber - minNumber)) + minNumber;
// Find number of digits
var n = num.toString();
n = n.length;
// If number is negative subtract 1 from length because of "-" sign
if (num < 0) {
n--;
}
// End: find number of digits
}
return num;
}
Well here's a version of your function that still uses exactly the same method (i.e., keeps generating numbers until it gets one with the right number of digits), but with the code duplication eliminated:
function generateRandomInteger(minNumber, maxNumber, minDigits, maxDigits) {
var num, digits;
do {
num = Math.floor(Math.random() * (maxNumber - minNumber)) + minNumber;
digits = Math.abs(num).toString().length;
} while (digits > maxDigits || digits < minDigits);
return num;
}
As for your concern about whether this is really random, the Math.random() method will give you a "pseudo-random" number, but at least you know it will work in all current browsers.
Try this functional approach, it creates an array and shuffles it randomly so it gives "very random" results. I've used it before with very satisfying results.
function getLen( v ) {
return Math.abs( v ).toString().length;
};
function randomInteger( min, max ) {
return ( new Array( ++max - min ) )
.join('.').split('.')
.map(function( v,i ){ return [ Math.random(), min + i ] })
.filter(function( v ){ return getLen( v[1] ) >= getLen( min ) })
.sort().map(function( v ) { return v[1] }).pop();
}

Categories

Resources