Overlapping loops inside functions - javascript

In code wars, i am training on a project of multiplicative inverse. The goal is, for example -- if "39" is the input the output should be "4" [39 = 3*9 ==> 27 = 2*7 => 14 = 1*4 ==> (4)].
i wrote some code which just multiplies the input for only first level(39 ==> 27).
My code until now,
function persistence(num) {
var digits = new Array();
digits = num.toString().split("").map(Number);
var res = 1;
for (i = 0; i < digits.length; i++) { res = res * digits[i]; }
return res;
console.log(persistence(digits));
}
i am just learning javascript and i am stuck here. I need to loop this process till i get a single digit number.
CAN SOMEONE PLEASE HELP ME?
Sorry if my question is not clear...

Array methods are your friend. In this case, use map and reduce:
function multiplyDigits(num) {
if (num < 10) return num;
console.log(num);
const multiplied = String(num)
.split('')
.map(Number)
.reduce((a, n) => a * n, 1);
return multiplyDigits(multiplied);
}
console.log(multiplyDigits(39));

Aside from formatting this is very similar to your code. I commented the only two changes:
function persistence(num) {
var digits = new Array();
digits = num.toString().split("").map(Number);
// 1) Added this if statement to return the result
// immediately if there is only one digit.
if ( digits.length === 1 )
return digits[0];
var res = 1;
for (i = 0; i < digits.length; i++)
res = res * digits[i];
// 2) Changed from `return res;` so that the function you wrote
// is called again on the result (if there were more than one digit).
return persistence(res);
}
console.log(persistence('39'));
For a bit shorter of a solution you could use:
function persistence(num) {
return num < 10
? num
: persistence( (num+'').split('').reduce( (a,b) => a*b ) );
}
console.log(persistence('39'));

Related

Why function returns wrong array of numbers if that number is big

I am working to solve a problem, I have an array of numbers for example [1, 2, 3] and I need to make from that array number 123 and add 1 and than return it like [1, 2, 4]. My code work with small numbers but with big it returns wrong number. Why?
var plusOne = function(digits) {
let num = parseInt(digits.join(''))
num = num + 1
let arr = num.toString().split().join(',')
let incrementedArr = []
for (let i = 0; i < arr.length; i++) {
incrementedArr.push(arr[i])
}
return incrementedArr;
};
When input is
[6,1,4,5,3,9,0,1,9,5,1,8,6,7,0,5,5,4,3]
my function returns
[6,1,4,5,3,9,0,1,9,5,1,8,6,7,0,5,0,0,0]
instead of
[6,1,4,5,3,9,0,1,9,5,1,8,6,7,0,5,5,4,4]
why I have three zeros in the end? Thank you!
The problem is with the way you are converting the number back to an array. Your code is using the split() method, which expects a separator as the argument, but you are passing an empty string. This causes the method to split the number into an array of characters, rather than numbers.
You should use the map() method instead, like this:
let incrementedArr = Array.from(num.toString()).map(Number);
This will convert the number back to a string, and then use the map() method to convert each character back to a number.
Another issue is with the way you are incrementing the number. You are incrementing the number after converting the array to a number. Instead of that you should use the last element of the array and increment it by 1 and use the rest of the array as it is.
let incrementedArr = digits.slice()
incrementedArr[incrementedArr.length-1] += 1
Also, you can use spread operator to return the incremented number.
return [...incrementedArr];
Here is the final code:
var plusOne = function(digits) {
let incrementedArr = digits.slice()
incrementedArr[incrementedArr.length-1] += 1
return [...incrementedArr];
};
I hope this helps!
As the maximum JavaScript precision would be exceeded by a number of this size, see #Barmar's comment, you may have to perform the addition and the carry-over manually and below is one approach:
const
d0 = [6,1,4,5,3,9,0,1,9,5,1,8,6,7,0,5,5,4,3],
d1 = [6,1,4,5,3,9,0,1,9,5,1,8,6,7,0,5,5,4,9],
d2 = [6,1,4,5,3,9,0,1,9,5,1,8,6,7,9,9,9,9,9],
plusOne = d => {
let adds = d.map((n,i,a) => i === a.length - 1 ? 1 : 0), newd = d;
do {
newd = newd.map((n,i) => n + adds[i]);
adds = newd.map((n,i) => n > 9 ? 1 : 0);
adds.push( adds.shift() );
newd = newd.map(n => n > 9 ? 0 : n);
} while( !adds.every(e => e === 0) );
return newd;
};
console.log( plusOne( d0 ) );
console.log( plusOne( d1 ) );
console.log( plusOne( plusOne( d1 ) ) );
console.log( plusOne( d2 ) );
This is probably what was meant to be done in the exercise
function plusOne(digits) {
const copy = [...digits]
for (let i = copy.length - 1; i >= 0; i -= 1) {
if (copy[i] < 9) {
copy[i] += 1
for (let j = i + 1; j < copy.length; j += 1) {
copy[j] = 0
}
return copy
}
}
return [1, ...'0'.repeat(copy.length)]
}
console.log(plusOne([6,1,4,5,3,9,0,1,9,5,1,8,6,7,0,5,5,4,3]).join(''))
console.log(plusOne([6,1,4,5,3,9,0,1,9,5,1,8,6,7,9,9,9,9,9]).join(''))
console.log(plusOne([9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9]).join(''))

Check if String has sequential or repeated characters in javascript (underscore)

I have code that I am trying to refactor. Im new to javascript so Im tring to make more readable code using functions in libraries like underscore.
The function below can detect when string
contains 3 or more ordered characters such as (234, efg, LmN)
and
when string contains 3 or more repeated (lll, 444, MMm, ###)
const input = "Dfdf123125";
const myStr = input.toLowerCase();
const n = 3;
let isRepeating = false;
let isSequential = false;
for (let i = 0; i < myStr.length; i++) {
if (i + (n - 1) <= myStr.length) {
let isRepeatingTemp = false;
let isSequentialTemp = false;
for (let j = i; j < i + n; j++) {
(myStr.charCodeAt(i) === myStr.charCodeAt(j)) ? isRepeatingTemp = true: isRepeatingTemp = false;
(myStr.charCodeAt(i) === myStr.charCodeAt(j) - (n - 1)) ? isSequentialTemp = true : isSequentialTemp = false;
}
if (isRepeatingTemp) isRepeating = true;
if (isSequentialTemp) isSequential = true;
}
}
Im trying to to see if I can optimize this and make it more readable with underscore and/or even make time/space complexity better. I know this can also be done with regx but im trying to get it done without it.
Instead of the inner for loop, I chunked the string to n using Array.prototype.slice() to see ahead n characters. I used Array.prototype.indexOf() to find if it's sequential based off the abc and num constants(ref). To see if it's repeating, I used Array.prototype.every() that loops through the chunk and check if they're similar and return a boolean based on the expression.
The result gives the output of each instance found, and if it was sequential or repeating.
const input = "Dfdf123125";
function RepSeq(str, n) {
var rep = false;
var seq = false;
var result = [];
const num = '0123456789';
const abc = 'abcdefghijklmnopqrstuvqxyz';
if (str.length < n) return false;
for (var i = 0; i < str.length; i++) {
if (i + n > str.length) break;
var chunk = str.slice(i, i + n);
var seqABC = abc.indexOf(chunk) > -1;
var seq123 = num.indexOf(chunk) > -1;
if (seq123 || seqABC) {
seq = true;
result.push(chunk);
}
if ([...chunk].every(v => v.toLowerCase() === chunk[0].toLowerCase())) {
rep = true;
result.push(chunk);
}
}
return {
repetition: rep,
sequential: seq,
out: result
};
}
console.log(RepSeq(input, 3));
// Output:
// {
// out: ["123"],
// repetition: false,
// sequential: true
// }
With this method, we're peeking at the string one block(i+n) at a time. Ex(n=3):
1. [Dfd]f123125
2. D[fdf]123125
3. Df[df1]23125
4. Dfd[f12]3125
5. Dfdf[123]125 - Sequential!
6. Dfdf1[231]25
7. Dfdf12[312]5
8. Dfdf123[125]

Multiplicative Persistence Codewars Challenge

I've been working on a kata from Codewars, the challenge is to write a function, persistence, that takes in a positive parameter num and returns its multiplicative persistence, which is the number of times you must multiply the digits in num until you reach a single digit.
Example:
persistence(39) === 3 // because 3*9 = 27, 2*7 = 14, 1*4=4
// and 4 has only one digit
persistence(999) === 4 // because 9*9*9 = 729, 7*2*9 = 126,
// 1*2*6 = 12, and finally 1*2 = 2
persistence(4) === 0 // because 4 is already a one-digit number
While trying to figure this out I came across a solution online (shown below) and after trying to understand its logic, I couldn't see why the code didn't work
var count = 0;
function persistence(num) {
if (num.toString().length === 1) {
return count;
}
count++;
var mult = 1;
var splitStr = num.toString().split("");
for (var i = 0; i <= splitStr; i++) {
mult *= parseFloat(splitStr[i])
}
return persistence(parseFloat(mult));
}
The output for any single digit number will be 0 which is correct however for any number that is multiple digits, the persistence always logs as 1 and I can't seem to figure out why, any help would be greatly appreciated.
The posted code has quite a few problems.
for (var i = 0; i <= splitStr; i++) {
But splitStr is an array, not a number; i <= splitStr doesn't make sense. It should check against splitStr.length instead of splitStr.
Another problem is that it should use i <, not i <=, else the final splitStr[i] will be undefined.
Another problem is that the count variable is global, so more than one call of persistence will result in inaccurate results. There's no need for a count variable at all. To fix it:
function persistence(num) {
if (num.toString().length === 1) {
return 0;
}
var mult = 1;
var splitStr = num.toString().split("");
for (var i = 0; i < splitStr.length; i++) {
mult *= parseFloat(splitStr[i])
}
return 1 + persistence(parseFloat(mult));
}
console.log(
persistence(999),
persistence(39),
persistence(4)
);
Or, one could avoid the for loop entirely, and use more appropriate array methods:
function persistence(num) {
const str = num.toString();
if (str.length === 1) {
return 0;
}
const nextNum = str.split('').reduce((a, b) => a * b, 1);
return 1 + persistence(nextNum);
}
console.log(
persistence(999),
persistence(39),
persistence(4)
);
or we can use while loop with reduce array method
const persistence=(num)=>{
let splitNumArr=num.toString().split('')
let newList
let count=0
while(splitNumArr.length>1){
newList=splitNumArr.reduce((acc,curr)=>{
return acc*=curr
})
splitNumArr=newList.toString().split('')
count++
}
return count
}
console.log(persistence(39))===3
console.log(persistence(999))===4
console.log(persistence(9))===0

Missing number in array

I encountered a problem when I started searching for an element from an array by sorting:
function missingnumber(numbers) {
var missing = -1;
var sorted = numbers.sort(function(a, b) {
a - b
})
for (var i = sorted[0]; i < numbers.length - 1; i++) {
if (numbers(i) === -1) {
missing = i
}
}
return missing;
}
var numbers = [2,4,10,7,6,11,8,9,12]//5 without sorting
var numbers = [11,19,18,17,15]//i am getting -1 with sorting
console.log(missing - number(numbers))
I'm trying to get the the missing number by sorting and it gives me missing number -1. Where is hole in my logic?
There are numerous syntax and logic errors in your code; here are a few:
if (numbers(i) === -1) { has a syntax error (you probably mean numbers[i] as an array index) and a logic error (comparing an array index against -1 won't tell you whether it's the missing number or not, unless the missing number happens to be -1).
console.log(missing - number(numbers)) is where you're (rightfully, at least somewhere in the code) trying to calculate the missing number by subtraction. Unfortunately, this isn't syntactically or logically correct.
var i = sorted[0] should be simply var i = 0 rather than the value of the element at index 0 in sorted.
Here's a working version; if there are multiple missing numbers, it returns the first one, and it's assumed that the step size is always 1 in the sequence:
const missing = nums => {
nums.sort((a, b) => a - b);
for (var i = 1; i < nums.length; i++) {
if (nums[i] - nums[i-1] !== 1) {
return nums[i-1] + 1;
}
}
return -1;
};
console.log(missing([2,4,10,7,6,11,8,9,12]));
console.log(missing([11,19,18,17,15]));
Codility missing number in array solution 100% performance
func missingNumber( array: [Int]) -> Int {
let length = array.count+1
let totalSum = length * (length+1)/2
let actualSum = array.reduce(0, { x, y in
x + y
})
return totalSum - actualSum
}
Another solutions is
public func solution(_ array : inout [Int]) -> Int {
// write your code in Swift 4.2.1 (Linux)
var dict: [Int: Int] = [:]
array.map{
dict[$0] = $0
}
var missingNumber = 1
for (_, _) in dict {
if dict[missingNumber] == nil {
return missingNumber
}
missingNumber = missingNumber+1
}
return missingNumber
}

Javascript Loop Performance: Counting occurrences of a number in a finite series

What is the most efficient way to write a javascript loop to calculate the number of occurrences of 7's (as an example number) that will be encountered in counting from 1 to 100?
Example:
function numberOccurences(targetNumber, minNumber, maxNumber) {
var count = 0;
for (i = minNumber; i < maxNumber; i++) {
count = count + (i.toString().split(targetNumber).length - 1);
}
return count;
}
var result = numberOccurences(7,1,100);
This will do it without looking at the actual numbers. Sorry, no loop, but you did ask for effeciency. If you really want to use a loop, make the recursion an iteration.
function digitOccurences(digit, min, max, base) {
if (typeof base != "number") base = 10;
return digitOccurencesPlus(digit, max, base, 1, 0) - digitOccurencesPlus(digit, min, base, 1, 0);
function digitOccurencesPlus(digit, N, base, pow, rest) {
if (N == 0) return 0;
var lastDigit = N%base,
prevDigits = (N-lastDigit)/base;
var occsInLastDigit = pow*(prevDigits+(lastDigit>digit));
var occsOfLastInRest = rest * (lastDigit==digit);
// console.log(prevDigits+" "+lastDigit, rest, occsInLastDigit, occsOfLastInRest);
return occsInLastDigit + occsOfLastInRest + digitOccurencesPlus(digit, prevDigits, base, pow*base, pow*lastDigit+rest);
}
}
This is an interesting problem, and already has similar answers for other languages. Maybe you could try to make this one in javascript: Count the number of Ks between 0 and N
That solution is for occurences from 0 to n, but you could easily use it to calculate from a to b this way:
occurences(a,b)= occurences(0,b)-occurences(0,a)
This is much faster (x6) than my original function...JSPERF
function numberOccurences2(targetNumber, minNumber, maxNumber) {
var strMe = "";
for (i = minNumber; i < maxNumber; i++) {
strMe = strMe.concat(i);
}
var re = new RegExp(targetNumber,"g");
var num1 = strMe.length;
var num2 = strMe.replace(re, "").length;
num2 = num1- num2;
return (num2);
}
There has to be a faster way still...

Categories

Resources