I need to extract every nth char of a string in Javascript - 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.

Related

4 numbers max variance calculation

I have an array of four numbers, something like [597103978, 564784412, 590236070, 170889704] and I need to make sure that the variance is no more than 10%, for example for the array above, the check must fail because of the number 170889704.
Can someone suggest me a good method how to do that is Javascript?
Thanks in advance!
I would do it using Array.every
const arr = [597103978, 564784412, 590236070, 170889704];
const variance = (n, m) => {
return Math.abs( (n - m) / n );
};
const isLessThanTenPercent = (n) => {
return ( n < 0.1 );
};
const arrayIsGood = arr.every((n, i) => {
// m is the next element after n
const m = arr[i+1];
if (Number.isInteger(m)) {
const v = variance(n, m);
return isLessThanTenPercent(v);
} else {
// if m is not an integer, we're at the last element
return true;
}
});
console.log({arrayIsGood});

reduce sum of digits recursivel down to a one digit number

I'm trying to solve a challenge (Digit Degree) on Code signal where the task is to find the the number of times we need to replace this number with the sum of its digits until we get to a one digit number. I.e. of the incoming number is 5 it's already a one digit number so the outcome should be 0. If the number is 100 the sum of its digits is 1 which is one digit so the outcome should be 1 and so on...
I'm doing a recursive solution like this:
let count = 0;
function digitDegree(n) {
if (n < 10) {
console.log(count);
return count;
};
const arr = n.toString().split('').map(Number);
const sumOfDigits = arr.reduce((acc, curr) => acc + curr);
count++;
digitDegree(sumOfDigits);
}
At the second loop and forth I'm getting null as output even if the console log shows the correct value. Where does it go wrong?
I saw that the question was up before but the answer was quite mathematical. Would this approach be ok or would it be considered bad practise?
You need a return statement for getting the result of the recursion.
return digitDegree(sumOfDigits);
A shorter approach would remove explicit conversions in advance and remove temporary arrays.
Then take another parameter for count and omit a global variable.
function digitDegree(n, count = 0) {
if (n < 10) return count;
return digitDegree(
n .toString()
.split('')
.reduce((acc, curr) => acc + +curr, 0),
count + 1
);
}
console.log(digitDegree(9999));
To return a value, update the last line in your function to return digitDegree(sumOfDigits)
function digitDegree(n) {
if (n < 10) {
console.log(count);
return count;
};
const arr = n.toString().split('').map(Number);
const sumOfDigits = arr.reduce((acc, curr) => acc + curr);
count++;
// add return
return digitDegree(sumOfDigits);
}
Pitfalls with your current approach:
It's impure.
digitDegree(100) returns 1 the first time you run it but returns 2 when you run it again. This is because count was declared outside the function (making it global)
let count = 0
function digitDegree(n) {
if (n < 10) {
return count;
};
const arr = n.toString().split('').map(Number);
const sumOfDigits = arr.reduce((acc, curr) => acc + curr);
count++;
return digitDegree(sumOfDigits);
}
// wrong - output should not change
console.log(digitDegree(100)) //=> 1
console.log(digitDegree(100)) //=> 2
console.log(digitDegree(100)) //=> 3
Make your function pure
A pure function is a specific kind of value-producing function that not only has no side effects but also doesn’t rely on side effects from other code—for example, it doesn’t read global bindings whose value might change.
A pure function has the pleasant property that, when called with the same arguments, it always produces the same value (and doesn’t do anything else)
Source
Suggestions:
Pass count as an argument
function digitDegree(n,count=0) {
if (n < 10) {
return count;
};
const arr = n.toString().split('').map(Number);
const sumOfDigits = arr.reduce((acc, curr) => acc + curr);
count++;
return digitDegree(sumOfDigits, count);
}
// correct
console.log(digitDegree(100)) //=> 1
console.log(digitDegree(100)) //=> 1
console.log(digitDegree(100)) //=> 1
Wrap your recursion function inside another function
function recursionWrapper(num){
let count = 0;
function digitDegree(n) {
if (n < 10) {
return count;
};
const arr = n.toString().split('').map(Number);
const sumOfDigits = arr.reduce((acc, curr) => acc + curr);
count++;
// notice how we don't need a return in this approach
digitDegree(sumOfDigits)
}
digitDegree(num)
return count
}
// correct
console.log(recursionWrapper(100)) //=> 1
console.log(recursionWrapper(100)) //=> 1
console.log(recursionWrapper(100)) //=> 1
Further reading:
How to deal with dirty side effects in your pure functional JavaScript
Javascript and Functional Programming — Pt. 3: Pure Functions

Multiplying digits within a number - excluding zeros

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)

Saving count variable through recursion with only 1 argument

What's the best way to "save" the returned variable from the previous stack all the way to the first call using only one argument?
I know of 2 techniques to 'save' variables in recursion, but the test cases don't let me implement them that way.
Prompt: reverse a string using recursion.
Test cases:
should be invoked with one argument
should use recursion by calling itself
Attempt 1 (using helper function):
var reverse = function(string) {
var str = string.split('');
var reversed = [];
var helper = function(i) {
reversed.unshift(str[i]);
if (i < str.length) {
i++;
helper(i);
}
};
helper(0);
return reversed.join('');
}
Attempt 2 (without helper + using extra arguments)
var reverse = function(string, index, prev) {
var prev = prev || [];
index = index || 0;
if (index < string.length) {
prev.unshift(string[index]);
index++;
reverse(string, index, prev);
}
return prev.join('');
};
What would be the 3rd way of doing this?
Thanks!
Source: #9 from https://github.com/JS-Challenges/recursion-prompts/blob/master/src/recursion.js
You don't need to save anything. If you order the return correctly the call stack will unwind and create the reversed string for you:
var reverse = function(string) {
if (string.length == 0) return string // base case
return reverse(string.slice(1)) + string[0] // recur
};
console.log(reverse("hello"))
By returning the result of the recursion before the first character you wind and unwind the stack before the first call returns. You can then get result without maintaining any state other than the call stack.
I'd store the information to be used later in the function body only, without passing it down the call chain:
var reverse = function(string) {
const { length } = string;
return string[length - 1] + (
string.length === 1
? ''
: reverse(string.slice(0, length - 1))
);
};
var reverse = function(string) {
const { length } = string;
return string[length - 1] + (
string.length === 1
? ''
: reverse(string.slice(0, length - 1))
);
};
console.log(reverse('foo bar'));
Others have shown better ways to write your reverse recursively.
But as to the actual question you asked, modern JS allows for default arguments. I tend not to use them very much, but they are very useful in JS to allow you to write this sort of recursion without helper functions. Thus,
const reverse = (string, index = 0, prev = []) => {
if (index < string.length) {
prev .unshift (string [index])
reverse (string, index + 1, prev)
}
return prev .join ('')
}
console .log (
reverse ('abcde')
)
Again, other answers have better versions of reverse. But this should show you how you can have a function that takes only one public variable and yet still uses its extra arguments.
Here's another way you can do it using destructuing assignment and a technique called continuation-passing style -
const cont = x =>
k => k (x)
const Empty =
Symbol ()
const reverse = ([ s = Empty, ...more ]) =>
s === Empty
? cont ("")
: reverse
(more)
(rev => cont (rev + s))
reverse ("hello world") (console.log)
// dlrow olleh
But watch out for really big strings -
const bigString =
"abcdefghij" .repeat (1000)
reverse (bigString) (console.log)
// RangeError: Maximum call stack size exceeded
Here's another technique called a trampoline which allows to think about the problem recursively but have a program that is both fast and stack-safe. Have your cake and eat it, too -
const recur = (...values) =>
({ recur, values })
const loop = f =>
{ let r = f ()
while (r && r.recur === recur)
r = f (...r.values)
return r
}
const reverse = (s = "") =>
loop // begin loop ...
( ( r = "" // state variable, result
, i = 0 // state variable, index
) =>
i >= s.length // terminating condition
? r // return result
: recur // otherwise recur with ...
( s[i] + r // next result
, i + 1 // next index
)
)
const bigString =
"abcdefghij" .repeat (1000)
console .log (reverse (bigString))
// jihgfedcba...jihgfedcba

Clearing a counter after each function call: JavaScript Recursive function

I have the folllowing solution to a problem relating to multiplicative persistence. However, I need to wipe the counter after each function call.
I have tried different return statements, counters and arrays.
I don't seem to be able to clear the counter after each function call AND
get the correct answer. It is adding all the answers from multiple function calls.
function persistence(num, counter = 0) {
if (num.toString().length != 1) {
num = num.toString().split("").filter(Number).reduce((a, b) => a * b);
persistence(num, ++counter);
}
return counter;
}
persistence(999) // Answer should be 4.
persistence(25)// Answer should be 2 not 6 or 1.
The tests here:
describe('Initial Tests', function () {
Test.assertEquals(persistence(39),3);
Test.assertEquals(persistence(4),0);
Test.assertEquals(persistence(25),2);
Test.assertEquals(persistence(999),4);
});
You need to return the result of each recursive call and handle the else case.
Try this:
function persistence(num, counter = 0) {
if (num.toString().length != 1) {
num = num.toString().split("").filter(Number).reduce((a, b) => a * b);
return persistence(num, ++counter);
} else {
return counter;
}
}
Here are the results from console:
> persistence(25)
< 2
> persistence(999)
< 4
I'm assuming you're trying to compute multiplicative digital root but that does not remove zeroes from the computation as you're doing with .filter(Number) above. Below, we write multiplicativeRoot which returns an array of the steps it takes to reduce a number to a single digit
Finally, the multiplicative persistence can be computed by simply counting the number of steps in the return value from multiplicativeRoot and subtracting 1 (the first value in the result is always the input value)
The result is an implementation of multiplicativePersistence that is made up of several functions, each with their distinct and clear purpose
const digits = n =>
n < 10
? [ n ]
: digits (n / 10 >> 0) .concat ([ n % 10 ])
const mult = (x,y) =>
x * y
const product = xs =>
xs.reduce (mult, 1)
const multiplicativeRoot = x =>
x < 10
? [ x ]
: [ x ] .concat (multiplicativeRoot (product (digits (x))))
const multiplicativePersistence = x =>
multiplicativeRoot (x) .length - 1
console.log (multiplicativeRoot (999)) // [ 999, 729, 126, 12, 2 ]
console.log (multiplicativePersistence (999)) // 4
console.log (multiplicativeRoot (25)) // [ 25, 10, 0 ]
console.log (multiplicativePersistence (25)) // 2

Categories

Resources