how to replace some character with certain repeting regex - javascript

this is the log
console.log(duckShoot(4, 0.64, '|~~2~~~22~2~~22~2~~~~2~~~|'));
the output must be====>|~~X~~~X2~2~~22~2~~~~2~~~|
here the code i've try:
function duckShoot(ammo, aim, ducks) {
let shot = Math.floor(ammo * aim)
// console.log(shot);
return ducks.replace (/2/g, "X")
}
how to make /2/g just replace certain repeating
i wanna make code above same function with this
function duckShoot(ammo, aim, ducks) {
let shot = Math.floor(ammo * aim)
// console.log(shot);
for (let i = 1; i <= shot; i++) {
ducks = ducks.replace("2", "X");
}
return ducks
}

let c = 2; // how many you want to replace
'|~~2~~~22~2~~22~2~~~~2~~~|'.replaceAll('2', o => (c-- >= 0) ? 'X':o )
or you can keep the 'old' replace with the regex
'|~~2~~~22~2~~22~2~~~~2~~~|'.replace(/2/g, o => (c-- >= 0) ? 'X':o )
whereas
(o) => (c-- >= 0) ? 'X':o
is a simple function decreasing the counter and returning an 'X' or keep the o(riginal)

Related

JavaScript keep the original array in recursive function

I would like to keep the original array to return the original index in recursive function.
The original code is from rbarilani https://gist.github.com/rbarilani/0d7946510740f9e1e8fa .
Please help to advise how to change the line
const numList = [3,9,8,4,5.5,7,10.07];
function subsetSum(numbers, target, partial) {
var s, n, remaining;
const numList = [3,9,8,4,5.5,7,10.07]; **//<<<<<<<The code I want to change, please advise how to make it as function input**
partial = partial || [];
// sum partial
s = partial.reduce(function (a, b) {
return Math.round((a + b)*100)/100;
}, 0);
// check if the partial sum is equals to target
if (s === target) {
console.log(numList);
partial.forEach(function(findIndex){
console.log(findIndex, 'is at position ', numList.indexOf(findIndex));
});
}
for (var i = 0; i < numbers.length; i++) {
n = numbers[i];
remaining = numbers.slice(i + 1);
subsetSum(remaining, target, partial.concat([n]));
}
}
subsetSum([3,9,8,4,5.5,7,10.07],15.57);
thank you all
You need to create a closure around your recursive function like:
function findSubSet(numList,targ){
function subsetSum(numbers, target, partial) {
var s, n, remaining;
partial = partial || [];
// sum partial
s = partial.reduce(function (a, b) {
return Math.round((a + b)*100)/100;
}, 0);
// check if the partial sum is equals to target
if (s === target) {
console.log(numList);
partial.forEach(function(findIndex){
console.log(findIndex, 'is at position ', numList.indexOf(findIndex));
});
}
for (var i = 0; i < numbers.length; i++) {
n = numbers[i];
remaining = numbers.slice(i + 1);
subsetSum(remaining, target, partial.concat([n]));
}
}
subsetSum(numList,targ);
}
findSubSet([3,9,8,4,5.5,7,10.07],15.57);
Your function subsetSum() does not return anything, so it is more like a recursive procedure really. Everything in your code stays the same, the only change I made was to create the function findSubSet() around it, so it keeps the original numList array in its scope to be used by all recursive calls of subsetSum().
Using the closure idea, you can simplify your code even further, as the target value is another variable that does not need to be passed down:
function findSubSet(numList,target){
function subsetSum(numbers,partial) {
var s, n, remaining;
// sum partial
s = partial.reduce((a, b)=>Math.round((a + b)*100)/100, 0);
// check if the partial sum is equals to target
if (s === target) {
console.log("found a subset in "+numList.join(" ")+" for target "+target+":");
partial.forEach(idx=>console.log(idx, 'is at position ', numList.indexOf(idx)));
}
for (var i = 0; i < numbers.length; i++)
subsetSum(numbers.slice(i + 1), partial.concat([numbers[i]]));
}
subsetSum(numList,[]);
}
findSubSet([3,9,8,4,5.5,7,10.07],17.5);
I will recommend generators as they are perfectly suited for this kind of problem. The benefit of the generator is that it is pauseable and cancellable. This allows you to easily find one solution to the problem, or all solutions, without having to change the code.
function* subsetSums(numbers, target, precision = 2)
{ function* solve(i, q, r)
{ if (q == 0) return yield r
if (numbers.length < i || q < 0) return
// solve with this number
yield *solve
( i + 1
, round(q - numbers[i], precision)
, [...r, {pos: i, n: numbers[i]}]
)
// solve without this number
yield *solve(i + 1, q, r)
}
yield *solve(0, target, [])
}
Notice how I separated round into its own function. Isolating concerns is an effective programming technique as it makes your functions easier to read/write and promotes code reuse within other areas of your program
const round = (n, p = 0) =>
Math.round(n * 10 ** p) / 10 ** p
We can get all solutions -
const solutions =
Array.from(subsetSums([3.27,9,8,6.8,4,5.5,7,10.07], 15.57))
Or maybe we just want the first solution. Because generators are cancellable, this means that no work will be done after returning the first value -
function first (it)
{ for (const v of it)
return v
}
const solution =
first(subsetSums([3.27,9,8,6.8,4,5.5,7,10.07], 15.57))
We could wrap this into a simple HTML form using some additional generic functions, stepper, which steps through any generator, and json, which creates a text node with JSON.stingify'd contents -
function* stepper (it, f)
{ let x = it.next()
while (!x.done) (yield f(x.value), x = it.next())
while (true) yield f("no more results")
}
function json(value)
{ const e = document.createElement("pre")
e.textContent = JSON.stringify(value)
return e
}
Now all we have to do is connect this to our form -
<form id="solver">
<button type="button" name="next">next</button>
<output name="output"></output>
</form>
const f =
document.forms.solver
const solver =
stepper
( subsetSums([3.27,9,8,6.8,4,5.5,7,10.07], 15.57)
, solution =>
f.output.appendChild(json(solution))
)
f.next.addEventListener("click", _ => solver.next())
Run the snippet below to see the results in your own browser -
function* subsetSums(numbers, target, precision = 2)
{ function* solve(i, q, r)
{ if (q == 0) return yield r
if (numbers.length < i || q < 0) return
// solve with this number
yield *solve
( i + 1
, round(q - numbers[i], precision)
, [...r, {pos: i, n: numbers[i]}]
)
// solve without this number
yield *solve(i + 1, q, r)
}
yield *solve(0, target, [])
}
function* stepper (it, f)
{ let x = it.next()
while (!x.done) (yield f(x.value), x = it.next())
while (true) yield f("no more results")
}
function json(value)
{ const e = document.createElement("pre")
e.textContent = JSON.stringify(value)
return e
}
const round = (n, p = 0) =>
Math.round(n * 10 ** p) / 10 ** p
const f =
document.forms.solver
const solver =
stepper
( subsetSums([3.27,9,8,6.8,4,5.5,7,10.07], 15.57)
, solution =>
f.output.appendChild(json(solution))
)
f.next.addEventListener("click", _ => solver.next())
<form id="solver">
<button type="button" name="next">next</button>
<output name="output"></output>
</form>
[{"pos":0,"n":3.27},{"pos":3,"n":6.8},{"pos":5,"n":5.5}]
[{"pos":5,"n":5.5},{"pos":7,"n":10.07}]
"no more results"
The numbers input is not modified as a result of running subsetSums.

I cant get my code to check if a number is already in a array | JavaScript

var usedNumbers = []
var counter = 0
while(counter < 9){
var math = Math.floor(Math.random() * 9)
if(math != usedNumbers){
usedNumbers[counter] = math
counter++
}
}
console.log(usedNumbers)
i am really bad at explaining and really new to coding but i will do my best
i want my piece of code to create a random number, check if that number is used before and then put it in the array so i can use it later.
but for some reason the if statement is always true so it doesnt check for duplicates
if someone can explain what i did wrong and how to fix it that would be great
You could take a Set and check only the size of it.
const numbers = new Set;
while (numbers.size < 9) numbers.add(Math.floor(Math.random() * 9));
console.log(...numbers);
You can use the array method .includes
var usedNumbers = []
var counter = 0
while(counter < 9){
var math = Math.floor(Math.random() * 9)
if(!usedNumbers.includes(math)){
usedNumbers[counter] = math
counter++
}
}
console.log(usedNumbers.sort())
Here is a functional and recursive way of doing it.
const saveNums = (currentNum, size, result) => {
if (result.length >= size) {
return result;
}
const newResult = result.includes(currentNum) ? result : [...result, currentNum];
return saveNums(Math.floor(Math.random() * size), size, newResult);
};
console.log(saveNums(Math.floor(Math.random() * 9), 9, []));

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.

Disqualifying consecutive characters in an Alphabetical Order. Sol [ASCII Format]

I was given this problem by my friend. The question asks to remove all the alphabetically consecutive characters from the string input given.
So I did it using Javascript, I need expert help if I performed it precisely.
I thought using Array.prototype.reduce will be the best way, do we have other possible ways?
/**
* #author Abhishek Mittal <abhishekmittaloffice#gmail.com>
* #description function can deal with both any types followed in a consecutive manner in ASCII Chart.
* #param {string} str
*/
function improvise(str) {
// Backup for original input.
const bck = str || '';
const bckArr = bck.split('').map( e => e.charCodeAt(0)); // converting the alphabets into its ASCII for simplicity and reducing the mayhem.
let result = bckArr.reduce( (acc, n) => {
// Setting up flag
let flag1 = n - acc.rand[acc.rand.length - 1];
let flag2 = n - acc.temp;
if(flag1 === 1 || flag2 === 1) {
(flag2 !== NaN && flag2 !== 1) ? acc.rand.pop() : null; // update the latest value with according to the case.
acc.temp = n
}else{
acc.rand.push(n); // updating the random to latest state.
acc.temp = null;
}
return acc;
}, {rand: [], temp: null} /* setting up accumulative situation of the desired result */)
result = result.rand.map(e => String.fromCharCode(e)).join('')
return result ? result : '' ;
}
function init() {
const str = "ab145c";
const final = improvise(str);
console.log(final)
}
init();
Well, the output is coming out to be correct.
Input: ab145c
Output: 1c
There's no way to solve this using any remotely reasonable regular expression, unfortunately.
I think it would be a lot clearer to use .filter, and check whether either the next character or the previous character is consecutive:
const code = char => char
? char.charCodeAt(0)
: -2; // will not be === to any other codes after addition or subtraction
function improvise(str) {
return [...str]
.filter((char, i) => {
const thisCode = code(char);
return (
thisCode !== code(str[i - 1]) + 1
&& thisCode !== code(str[i + 1]) - 1
);
})
.join('');
}
console.log(improvise('ab145c'));
(alternatively, you could check only whether the next character is consecutive, but then you'd have to check the validity of the last character in the string as well)
If you need continuously replace characters until no consecutive characters remain, then keep calling improvise:
const code = char => char
? char.charCodeAt(0)
: -2; // will not be === to any other codes after addition or subtraction
function improvise(str) {
return [...str]
.filter((char, i) => {
const thisCode = code(char);
return (
thisCode !== code(str[i - 1]) + 1
&& thisCode !== code(str[i + 1]) - 1
);
})
.join('');
}
let result = 'hishakmitalaaaaabbbbbbcccccclmnojqyz';
let same = false;
while (!same) {
const newResult = improvise(result);
if (newResult !== result) {
result = newResult;
console.log(result);
} else {
same = true;
}
}
console.log('FINAL:', result);
Well, that's great code but it doesn't gives the exact solution to the problem, see:
INPUT: hishakmitalaaaaabbbbbbcccccclmnojqyz
i got
Output: shakmitalaaaabbbbcccccjq
you see 'ab' & 'bc' remains intact, we need to increase the number of loops maybe to check those, can increase complexity as well.
But, my solution doesn't as well gives me the answer I desire e.g. for the above string I should get
ishakmitalaacccjq
but rather my solution gives
shakmitalcccccjq
hope you understand the question. We need a change in the way we traverse throughout the string.

Adding two numbers JS

I want to add two numbers from range 10-99,for example:
Input:16
Output:1+6=7
Input:99
Output:18
function digital_root(n) {
var z = n.toString().length;
if (z == 2) {
var x = z[0] + z[1]
return x;
}
}
console.log( digital_root(16) );
Output from this code is NaN.What should I correct?
You can try this:
function digital_root(n) {
var z = n.toString();
//use length here
if (z.length == 2) {
//convert to int
var x = parseInt(z[0]) + parseInt(z[1]);
return x;
} else {
return "not possible!";
}
}
console.log( digital_root(16) );
console.log( digital_root(99) );
console.log( digital_root(999) );
Use split to split the string in half and add the two using parseInt to convert to a number.
const sum = (s) => (''+s).split('').reduce((a,b) => parseInt(a)+parseInt(b))
↑ ↑ ↑ ↑
our coerce split sum
function to string in two both
Here a test :
const sum = (s) => (''+s).split('').reduce((a,b) => parseInt(a)+parseInt(b))
console.log(sum(12))
There are several approaches to sum digits of a number. You can convert it to a string but IDK if thats neccesary at all. You can do it with numerical operations.
var input = 2568,
sum = 0;
while (input) {
sum += input % 10;
input = Math.floor(input / 10);
}
console.log(sum);
Here's a fun short way to do it:
const number = 99
const temp = number.toString().split('')
const res = temp.reduce((a, c) => a + parseInt(c), 0) // 18
1.) Convert number to string
2.) Separate into individual numbers
3.) Use reduce to sum the numbers.
Your way would be the iterational way to solve this problem, but you can also use a recursive way.
Iterative solution (Imperative)
n.toString() Create String from number.
.split("") split string into chars.
.reduce(callback, startValue) reduces an array to a single value by applying the callback function to every element and updating the startValue.
(s, d) => s + parseInt(d) callback function which parses the element to an integer and adds it to s (the startValue).
0 startValue.
Recursive solution (Functional)
condition?then:else short-hand if notation.
n<10 only one digit => just return it.
n%10 the last digit of the current number (1234%10 = 4).
digital_root_recurse(...) call the function recursivly.
Math.floor(n / 10) Divide by 10 => shift dcimal point to left (1234 => 123)
... + ... add the last digit and the return value (digital root) of n/10 (1234 => 4 + root(123)).
function digital_root_string(n) {
return n.toString().split("").reduce((s, d) => s + parseInt(d), 0);
}
function digital_root_recurse(n) {
return n < 10 ? n : n % 10 + digital_root_recurse(Math.floor(n / 10));
}
console.log(digital_root_string(16));
console.log(digital_root_string(99));
console.log(digital_root_recurse(16));
console.log(digital_root_recurse(99));
The issue in your code is that you stored the length of n into z. The length is an integer, so both z[0] and [1] are undefined. The solution is to store the string into another variable and use that instead of z.
function digital_root(n) {
n = n.toString();
var l = n.length;
if (l === 2) {
return parseInt(n[0], 10) + parseInt(n[1], 10);
}
}
console.log( digital_root(16) );
Simply use var x = parseInt(n/10) + (n%10); and it will work for you.
function digital_root(n) {
var z = n.toString().length;
if (z == 2) {
var x = parseInt(n/10) + (n%10);
return x;
}
}
console.log( digital_root(16) );
console.log( digital_root(99) );
console.log( digital_root(62) );
Convert input to string, split it, convert each item back to number and sum them all:
function digital_root(n) {
return String(n).split('').map(Number).reduce((a,b) => a + b)
}
const result = digital_root(99);
console.log(result);

Categories

Resources