Multiplying digits within a number - excluding zeros - javascript

I have function taken from this example here that works well, except does not address any zeros that may be in the number, so everything is equaling zero when executing the function.
Multiplying individual digits in a number with each other in JavaScript
function digitsMultip(data) {
let arr = [];
for (let i of data) {
if (data[i] === 0) {
arr.push(data[i]);
}
}
return [...data.toString()].reduce((p, v) => p * v);
};
console.log(digitsMultip(3025));
I added to it a for-loop that accounts for the zero and remove it, but im doing something wrong here.
Uncaught TypeError: data is not iterable
DESIRED OUTPUT
3025 => 3 * 2 * 5 = 30

This iterates over the characters in your number. If the character is not "0" then it is added to the array. This array is then reduced by multiplying the values and then returned.
function digitsMultip(data) {
const arr = [];
for(let number of String(data)) {
if (number !== "0")
arr.push(number);
}
return arr.reduce((p, v) => p * v);
};
console.log(digitsMultip(3025));

You are getting that error because you are trying to iterate over a number.
Passing in a string or converting the number to string before iterating it would make it work.
Instead of looping it that way, a better and readable way would be to use the filter method to filter out the chars before multiplying:
function digitsMultip(data) {
return [...data.toString()].filter(n => n > '0').reduce((p, v) => p * v);
};
console.log(digitsMultip(3025));

Turn the input into a string, then split, filter the zeros and reduce multiplying
const input = 1203
const removeZeros = number =>{
const arr = number.toString().split('').filter(i => i !== '0')
return arr.reduce((a,c) => parseInt(a) * parseInt(c))
}
console.log(removeZeros(input))
One line version
const removeZeros = n => [...n.toString()].filter(c => c !== '0').map(x => parseInt(x)).reduce((a,c) => a*c)

Related

Why is my function sometimes squaring twice?

Writing a function to take a number, square each number and return them as a concatenated integer, ie. 3214 => 94116. For some reason, my code appears to occasionally square 2's and 3's twice making a 2 turn into 16 and 3 into 81. I can't figure it out. I'm not a super experienced debugger yet so any help would be appreciated.
function squareDigits(num){
let digits = (""+num).split("");
let intDigits = [];
for (x of digits) {
intDigits.push(parseInt(x));
}
for (x of intDigits) {
intDigits.splice(intDigits.indexOf(x), 1, x * x);
}
return parseInt(intDigits.join(""));
}
console.log(squareDigits(24));
Leaving aside the fact that you can do this more elegantly with something like map() the issue in your code is that it uses indexOf() while changing the values on each iteration. Since indexOf() returns the index of the first occurrence it is going to find digits that you have already replaced.
This is your original code with a few logs so you can understand what I mean:
function squareDigits(num){
let digits = (""+num).split("");
let intDigits = [];
for (x of digits) {
intDigits.push(parseInt(x));
}
for (x of intDigits) {
console.log('intDigits: ' + intDigits);
console.log(` index of ${x} = ${intDigits.indexOf(x)}`);
intDigits.splice(intDigits.indexOf(x), 1, x * x);
}
return parseInt(intDigits.join(""));
}
console.log('RESULT: ' + squareDigits(24));
Notice how in the second pass the index of 4 is 0 (the first position in the array) because you have replaced the original 2 by it's squared value 4.
A simple way to fix this is to not rely on indexOf() and iterate over the array the good old way, like this:
function squareDigits(num){
let digits = (""+num).split("");
let intDigits = [];
for (x of digits) {
intDigits.push(parseInt(x));
}
for (let i = 0; i < intDigits.length; i++) {
const x = intDigits[i];
console.log('intDigits: ' + intDigits);
console.log(` index of ${x} = ${i}`);
intDigits.splice(i, 1, x * x);
}
return parseInt(intDigits.join(""));
}
console.log('RESULT: ' + squareDigits(24));
A simplistic (and bug free) version of your function could be this:
const squareDigits = num => [...num.toString()].map(x => x ** 2).join('');
console.log(squareDigits(24));
Other variant:
const squareDigits = num => num.toString().replaceAll(/\d/g, x => x ** 2);
console.log(squareDigits(24));
Instead of looping twice use array methods .map() , .reduce() etc it will make your code effective .. wrote a simple function
See =>
function squareDigits(num){
let digits = String(num).split("");
digits = digits.reduce((final , digit)=> final += String( parseInt(digit) **2 ), "");
return digits
}
console.log(squareDigits(312));
As #Sebastian mentioned, intDigits.indexOf(x) will find the
first index. So after replacing the first one, there's a change you'll find the number you've just replaced.
We can simplify the function to :
function squareDigits(num){
return num.toString().split('').map(n => n ** 2).join('');
}
Where :
We convert the number to a string using toString()
We split the string into loose numbers using split('')
map() over each number
Return the square by using the Exponentiation (**) operator
join() the numbers to get the result
Example snippet:
function squareDigits(num){
return num.toString().split('').map(n => n ** 2).join('');
}
console.log(squareDigits(3214)); // 94116

How to sum an array of number which contains string in js?

My array:
const a = [
{
"baseFare": "1439.00",
},
{
"baseFare": "1739.00",
},
{
"baseFare": "1039.00",
},
]
Note: The number of values in const a will increase or decrease its user decisions ! there may be one or 5 or 7 values in the array !
How to sum all the values and output a single value , and in somecase if its only one value then the out put should be direct single value !
How to achive this ?
My code :
a.reduce((a, b) => a + b, 0)
you are almost there
try this,
a.reduce((a, b) => a + (+b.baseFare), 0);
//a is the accumulator , and it start with 0 its an integer
//If you need to access baseFare, then you have to get it from object b.baseFare,
//b.baseFare is a string so you have to convert it to a number (+b.baseFare) is for that
if you really need to get it as a floating point number, for ex: 5000, showing as "5000.00" then try this out
let sum = a.reduce((a, b) => a + (+b.baseFare), 0);;
sum = sum.toFixed(2); //"4217.00"
Just loop, converting the strings to numbers as you go:
let result = 0;
for (const entry of a) {
result += +entry.baseFare;
}
Or with destructuring:
let result = 0;
for (const {baseFare} of a) {
// ^^^^^^^^^^−−−−−−−−−−−−−−−−−−−−− destructuring
result += +baseFare;
}
That unary + is just one way to convert from string to number. I go into all your options in this other answer.

I need to extract every nth char of a string in Javascript

Ive been reading everything online but its not exactly what I need
var x = 'a1b2c3d4e5'
I need something to get me to
using 1 the answer should be abcde
using 2 the answer should be 12345
using 3 the answer should be b3e
the idea behind it if using 1 it grabs 1 skips 1
the idea behind it if using 2 it grabs 2 skips 2
the idea behind it if using 3 it grabs 3 skips 3
I dont want to use a for loop as it is way to long especially when your x is longer than 300000 chars.
is there a regex I can use or a function that Im not aware of?
update
I'm trying to some how implement your answers but when I use 1 that's when I face the problem. I did mention trying to stay away from for-loops the reason is resources on the server. The more clients connect the slower everything becomes. So far array.filter seem a lot quicker.
As soon as I've found it I'll accept the answer.
As others point out, it's not like regular expressions are magic; there would still be an underlying looping mechanism. Don't worry though, when it comes to loops, 300,000 is nothing -
console.time('while')
let x = 0
while (x++ < 300000)
x += 1
console.timeEnd('while')
// while: 5.135 ms
console.log(x)
// 300000
Make a big string, who cares? 300,000 is nothing -
// 10 chars repeated 30,000 times
const s =
'abcdefghij'.repeat(30000)
console.time('while string')
let x = 0
let interval = 2
let values = []
while (x < s.length)
{ values.push(s[x])
x += interval
}
let result = values.join('')
console.timeEnd('while string')
// while string: 31.990ms
console.log(result)
console.log(result.length)
// acegiacegiacegiacegiacegiacegiacegiacegia...
// 150000
Or use an interval of 3 -
const s =
'abcdefghij'.repeat(30000)
console.time('while string')
let x = 0
let interval = 3
let values = []
while (x < s.length)
{ values.push(s[x])
x += interval
}
let result = values.join('')
console.timeEnd('while string')
// while string: 25.055ms
console.log(result)
console.log(result.length)
// adgjcfibehadgjcfibehadgjcfibehadgjcfibe...
// 100000
Using a larger interval obviously results in fewer loops, so the total execution time is lower. The resulting string is shorter too.
const s =
'abcdefghij'.repeat(30000)
console.time('while string')
let x = 0
let interval = 25 // big interval
let values = []
while (x < s.length)
{ values.push(s[x])
x += interval
}
let result = values.join('')
console.timeEnd('while string')
// while string: 6.130
console.log(result)
console.log(result.length)
// afafafafafafafafafafafafafafafafafafafafafafa...
// 12000
You can achieve functional style and stack-safe speed simultaneously -
const { loop, recur } = require('./lib')
const everyNth = (s, n) =>
loop
( (acc = '', x = 0) =>
x >= s.length
? acc
: recur(acc + s[x], x + n)
)
const s = 'abcdefghij'.repeat(30000)
console.time('loop/recur')
const result = everyNth(s, 2)
console.timeEnd('loop/recur')
// loop/recur: 31.615 ms
console.log(result)
console.log(result.length)
// acegiacegiacegiacegiacegiacegiacegia ...
// 150000
The two are easily implemented -
const recur = (...values) =>
({ recur, values })
const loop = f =>
{ let acc = f()
while (acc && acc.recur === recur)
acc = f(...acc.values)
return acc
}
// ...
module.exports =
{ loop, recur, ... }
And unlike the [...str].filter(...) solutions which will always iterate through every element, our custom loop is much more flexible and receives speed benefit when a higher interval n is used -
console.time('loop/recur')
const result = everyNth(s, 25)
console.timeEnd('loop/recur')
// loop/recur: 5.770ms
console.log(result)
console.log(result.length)
// afafafafafafafafafafafafafafa...
// 12000
const recur = (...values) =>
({ recur, values })
const loop = f =>
{ let acc = f()
while (acc && acc.recur === recur)
acc = f(...acc.values)
return acc
}
const everyNth = (s, n) =>
loop
( (acc = '', x = 0) =>
x >= s.length
? acc
: recur(acc + s[x], x + n)
)
const s = 'abcdefghij'.repeat(30000)
console.time('loop/recur')
const result = everyNth(s, 2)
console.timeEnd('loop/recur')
// loop/recur: 31.615 ms
console.log(result)
console.log(result.length)
// acegiacegiacegiacegiacegiacegiacegia ...
// 150000
Since I'm not an expert of regex, I'd use some fancy es6 functions to filter your chars.
var x = 'a1b2c3d4e5'
var n = 2;
var result = [...x].filter((char, index) => index % n == 0);
console.log(result);
Note that because 0 % 2 will also return 0, this will always return the first char. You can filter the first char by adding another simple check.
var result = [...x].filter((char, index) => index > 0 && index % n == 0);
As a variant:
function getNth(str, nth) {
return [...str].filter((_, i) => (i + 1) % nth === 0).join('');
}
console.log(getNth('a1b2c3d4e5', 2)); // 12345
console.log(getNth('a1b2c3d4e5', 3)); // b3e
What I'd suggest, to avoid having to iterate over the entire array, is to step straight into the known nth's.
Here's a couple of flavors:
function nthCharSubstr(str, nth) {
let res = "";
for (let i = nth - 1; i < str.length; i += nth) {
res += string[i];
}
return res;
}
More ES6-y:
const nthCharSubstr = (str, nth) =>
[...Array(parseInt(str.length / nth)).keys()] // find out the resulting number of characters and create and array with the exact length
.map(i => nth + i * nth - 1) // each item in the array now represents the resulting character's index
.reduce((res, i) => res + str[i], ""); // pull out each exact character and group them in a final string
This solution considers this comment as being valid.

How to get a random number without duplicate digits in JavaScript/jQuery?

Update: The number can be started with zero.
I want to have a function like
function getRandomNumber(n){
...
}
I hope it gets a number with n digits while none of the digits is repeated. For instance:
getRandomNumber(3) -> 152 is what I want.
getRandomNumber(1) -> 6 is what I want.
getRandomNumber(6) -> 021598 is what I want. It can start with zero.
getRandomNumber(5) -> 23156 is what I want.
getRandomNumber(3) -> 252 is not because it has two 2.
getRandomNumber(5) -> 23153 is not because it has two 3.
Any simple way to do this?
On each call, make an array of digits, and then repeatedly pick random values and remove them from said array:
function getRandomNumber(n){
const digits = Array.from({ length: 10 }, (_, i) => i);
const result = Array.from({ length: n }, () => {
const randIndex = Math.floor(Math.random() * digits.length);
const digit = digits[randIndex];
digits.splice(randIndex, 1);
return digit;
});
return Number(result.join(''));
}
Array.from({ length: 10 }, () => console.log(getRandomNumber(8)));
By keeping an array as an hash map, an efficient solution is as follows. However keep in mind that unless it's a string a number can not start with 0.
function getRandomNumber(n){
var a = [],
x = ~~(Math.random()*10),
r = 0;
while (n) {
a[x] === void 0 && (a[x] = true, r += x*Math.pow(10,n-1), --n);
x = ~~(Math.random()*10);
}
return r;
}
console.log(getRandomNumber(3));
console.log(getRandomNumber(4));
console.log(getRandomNumber(5));
console.log(getRandomNumber(6));
console.log(getRandomNumber(7));
Don't how to deal with javascript but if it can help you, here a line of scala doing the job
def obtainRestrictedRandomNumber(): Long = scala.util.Random.shuffle((0 to 9)).mkString("").toLong
What it does is simply generating all digits from 0 to 9 then randomize them, concatenate the Array Int elements into a string for finally casting it into a Long.

Nesting ES6 array helper methods to generate an array of prime numbers

So I wanted to write a function that returns the sum of all prime numbers up to and including a provided number.
I have written this, which works:
function sumPrimes(num) {
const arr = Array.from({length: num+1}, (v, k) => k).slice(2);
return arr.filter(element => {
for(let i = 2; i < element; i++) {
if(element % i === 0) {
return false;
}
}
return element;
}).reduce((previous, current) => {
return previous += current;
}, 0);
}
sumPrimes(9);
I was thinking it would look much neater if the for loop was replaced with another array helper method. I'm struggling with the implementation of this however.
This is what I've got so far:
function sumPrimes(num) {
const arr = Array.from({length: num+1}, (v, k) => k).slice(2);
return arr.filter(element => {
return arr.find(ref => {
console.log("(" + element + " % " + ref + " === 0) " + (element % ref === 0));
if(element % ref === 0) { return false; }
return true;
});
}).reduce((previous, current) => {
return previous += current;
}, 0);
}
sumPrimes(20);
Written like this, the function no longer works as expected – it doesn't filter any of the numbers so all are summed by the .reduce helper. The console makes it appear like the if statement is still working as desired; what am I doing wrong?
You can reduce the range of research for primality of n at sqrt(n) :
var isPrime = n => n===2 ? true : Array(Math.ceil(Math.sqrt(n))+1).fill().map((e,i)=>i).slice(2).every(m => n%m);
var sumPrimes = num => Array(num).fill().map((e,i)=>i+1).slice(1).filter(isPrime).reduce((a,b) => a+b);
console.log(sumPrimes(9));
The reason your code doesn't work using find is because find is not a proper replacement for your for loop. The for loop you have here returns a boolean indicating if a divisor is found. find on the other hand, returns the divisor itself. This means all conditions for your filter method are numbers above 1, which all evaluate as truthy and hence nothing gets filtered.
The more appropriate method for your use case would be some or every.
These essentially work like find, except return a boolean as soon as they find an element satisfying the conditions.
some stops and returns true as soon as the predicate function returns true for some element.
Otherwise it returns false.
every stops and returns false as soon as the predicate function returns false for some element.
Otherwise it returns true.
One more issue would be that using a helper like this makes your code less efficient because you're now checking all numbers and not just up to the current number. This means your predicate function must include this equality check as well, or you'll have to first filter the array for all elements bellow the element being checked.
Another small improvement in terms of efficiency is that you don't need to iterate all the way up to element - 1 to find a divisor. Iterating up to sqrt(element) is enough because all numbers higher than sqrt(element) that divide element will allready have a complement divisor somewhere bellow sqrt(element).
Here's an approach using every and filtering the elements bellow the square root of the element being checked.
function sumPrimes(num) {
const arr = Array.from({length: num+1}, (v, k) => k).slice(2);
return arr.filter(element => {
return arr
.filter(ref => ref*ref <= element) // filter elements less than sqrt(current)
.every(ref => element % ref !== 0); // filter elements that have a divisor
}).reduce((previous, current) => {
return previous += current;
}, 0);
}
console.log(sumPrimes(9)); // 17
Perhaps a less functional but more efficient (and IMHO equally clean) way would be to just convert your for loop into a helper function:
function isPrime(element) {
for(let i = 2; i*i <= element; i++) {
if(element % i === 0) {
return false;
}
}
return true;
}
function sumPrimes(num) {
return Array
.from({ length: num+1 }, (v, k) => k)
.slice(2)
.filter(isPrime)
.reduce((previous, current) => previous + current, 0);
}
console.log(sumPrimes(9)); // 17

Categories

Resources