concatenation of arrays ES6 - javascript

I'm working on generating playoff brackets, and have gotten so far but am having trouble concatenating arrays. I can console.log the first array, console.log the second array, and console.log the concatenated array and it APPEARS to have the right number of items, but the first two are not in it when I look in the console.
My code (edited to add more functions):
startBracket(event: String, sortedTeams: Playoff[]) {
console.log('start bracket by filling teams...', this.BracketOrder.order);
console.log('contestants: ', sortedTeams);
// empty arrays
const leftMatches = [];
const rightMatches = [];
this.resetBracketData();
this.leftBracket.length = 0;
console.log('left bracket ', this.leftBracket);
console.log('right bracket ', this.rightBracket);
console.log('this.teams: ', this.teams);
console.log('this.BracketTeams: ', this.BracketOrder.teams);
// add teams to brackets
for (let i = 1; i <= this.BracketOrder.teams; i += 2) {
this.resetMatch();
// console.log(`Create matches: i=${i}`);
// Add team 1 to match
const place1 = this.BracketOrder.order.shift();
// console.log(place1);
const team1: String = `${place1} ${sortedTeams[place1 - 1].players}`;
this.Match.push(team1);
// Add team 2 to match
const place2 = this.BracketOrder.order.shift();
// console.log(place2);
// console.log('this Bracketorder.order ', this.BracketOrder.order);
const team2: String = `${place2} ${sortedTeams[place2 - 1].players}`;
this.Match.push(team2);
// console.log(this.Match);
// Add match to left or right side
if (i <= this.BracketOrder.teams / 2) {
leftMatches.push(this.Match);
} else {
rightMatches.push(this.Match);
}
}
// Add round to left and right brackets
// console.log(leftMatches);
// console.log(rightMatches);
this.pushRoundintoBrackets(leftMatches, rightMatches);
// fill remaining bracket rounds
this.fillBracket(event, sortedTeams);
}
pushRoundintoBrackets(leftMatches: String[][], rightMatches: String[][]) {
this.leftBracket.push(leftMatches);
this.rightBracket.push(rightMatches);
console.log('left bracket length ', this.leftBracket.length, this.leftBracket);
console.log('right bracket length ', this.rightBracket.length, this.rightBracket);
return true;
}
fillBracket(event: String, sortedTeams: Playoff[]) {
console.log('fillBracket begin...');
const nextRound = this.rounds - 1;
// for each round
let round = 0;
for (let x = nextRound; x >= 0; x--) {
const roundMatches = [];
const leftside: String[][] = [];
const rightside: String[][] = [];
const matches = Math.pow(x, 2);
let thisround = [];
thisround.length = 0;
console.log('starting round x: ', x, ' matches: ', matches);
console.log(`round: ${round}`);
// previous round (combined left and right bracket rounds)
console.log(this.leftBracket[round]);
console.log(this.rightBracket[round]);
thisround = [...this.leftBracket[round], ...this.rightBracket[round]];
console.log(`ROUND${round + 1}`, thisround);
// // add winners from previous round to next round
for (let y = 1; y <= matches * 2; y += 2) {
console.log(`MATCHES ${y} AND ${y + 1}`);
this.resetMatch();
const match1 = thisround.shift();
const match2 = thisround.shift();
// if bye, grab winner OR use placeholder
if (x > 0) {
console.log('X>0', x);
const winner1 =
match1.findIndex(e => e.includes('BYE')) === 1 ? match1[0].split(' ')[1] : `Winner of Match ${y}`;
const winner2 =
match2.findIndex(e => e.includes('BYE')) === 1 ? match2[0].split(' ')[1] : `Winner of Match ${y + 1}`;
// console.log(`winner1 ${winner1}`);
this.Match.push(winner1);
// console.log(`winner2 ${winner2}`);
this.Match.push(winner2);
console.log(`NEW MATCH ${this.Match}`);
// push match to correct side
if (y <= matches) {
leftside.push(this.Match);
console.log('left matches ', leftside);
} else {
rightside.push(this.Match);
console.log('right matches ', rightside);
}
} else {
console.log('SEMI-FINAL');
const winner1 = `Winner of Semi-Final`;
this.Match.push(winner1);
console.log(`NEW MATCH ${this.Match}`);
leftside.push(this.Match);
rightside.push(this.Match);
}
console.log(this.Match);
}
// // add the completed next round to the bracket
this.pushRoundintoBrackets(leftside, rightside);
round++;
}
// this.saveBracket(event);
}
Here is the console.log of that code:
What I SHOULD see is an array with the following (playoffs.page.ts: 775):
0: (2) ["Teisher / Tolentino", 'Winner of Match 2"],
1: (2) ["Oh / Collazos", "Winner of Match 4"],
3: (2) ["Petrillo / Cheney", "Winner of Match 6"],
4: (2) ["Tavernia / Schneider", "Winner of Match 8"]
But I'm only getting the last two and the first 2 matches don't show up.
Can someone please help me understand what I'm doing wrong? It is inside a loop, but that shouldn't matter since the logged parts are correct, right?

Related

Find the longest anagram with array javascript

I try to find the longest anagram in Javascript. For this, I have an array with 10 letters and a dictionary that contains every words.
I would like that the program test every combination possible.
We started from 10 (the array length of letters) and we check if it's an anagram
If not, we remove the char at the very end, and we check, if not, we shift the removed char by one to the left... When the entire combinations with 9 letters is tested, we test for 8, 7, 6, 5, 4, 3, 2 letters.
var wordFound = '' // The longest word found
var copyArr = [] // I don't manipulate the lettersChosen array, so I save a copy in copyArr
var savedWord = [] // A copy of copyArr but i'm not sure about this
var lengthLetters = 0 // The length of the numbers left
var lettersChosen = ['A', 'S', 'V', 'T', 'S', 'E', 'A', 'M', 'N'] //This the the array of letters
function isAnagram(stringA, stringB) {
stringA = stringA.toLowerCase().replace(/[\W_]+/g, "");
stringB = stringB.toLowerCase().replace(/[\W_]+/g, "");
const stringASorted = stringA.split("").sort().join("");
const stringBSorted = stringB.split("").sort().join("");
return stringASorted === stringBSorted;
}
function checkForEachWord(arr) {
strLetters = ''
for (i in arr)
strLetters = strLetters + arr[i]
for (var i in file)
if (isAnagram(strLetters, file[i])) {
wordFound = file[i]
return true
}
return false
}
function getOneOfTheLongestWord() {
lettersChosen.forEach(letter => {
copyArr.push(letter) // I copy the array
})
var index = 1 // The index of the letter to remove
var countLetter = 1 // How much letters I have to remove
var position = copyArr.length - index // The actual position to remove
var savedArray = [] // The copy of CopyArr but i'm not sure about that
var iteration = 0 // The total of combination possible
var test = checkForEachWord(copyArr) // I try with 10 letters
if (test == true)
return true // I found the longest word
while (test == false) {
copyArr.splice(position, 1) // I remove the char at current position
index++ // Change letter to remove
if (index > copyArr.length + 1) { // If I hit the first character, then restart from the end
index = 1
countLetter++ // Remove one more letter
}
console.log(copyArr + ' | ' + position)
position = copyArr.length - index // Get the position based on the actual size of the array letters
test = checkForEachWord(copyArr) // Test the anagram
copyArr = [] // Reset array
lettersChosen.forEach(letter => { // Recreate the array
copyArr.push(letter)
})
}
return true // Word found
}
getOneOfTheLongestWord()
My code is not optimal there is so many way to improve it.
Actually my output is good with 9 letters.
copyArr | position
A,S,V,T,S,E,A,M | 8
A,S,V,T,S,E,M,N | 6
A,S,V,T,S,A,M,N | 5
A,S,V,T,E,A,M,N | 4
A,S,V,S,E,A,M,N | 3
A,S,T,S,E,A,M,N | 2
A,V,T,S,E,A,M,N | 1
S,V,T,S,E,A,M,N | 0
But not with 8 letters, I don't see how I can use my countLetter to test all combinations...
Thank you very much.
Short answer, put the sorted versions of dictionary words into a trie, then do an A* search.
Longer answer because you probably haven't encountered those things.
A trie is a data structure which at each point gives you a lookup by character of the next level of the trie. You can just use a blank object as a trie. Here is some simple code to add a word to one.
function add_to_trie (trie, word) {
let letters = word.split('').sort();
for (let i in letters) {
let letter = letters[i];
if (! trie[letter]) {
trie[letter] = {};
}
trie = trie[letter];
}
trie['final'] = word;
}
An A* search simply means that we have a priority queue that gives us the best option to look at next. Rather than implement my own priority queue I will simply use an existing one at flatqueue. It returns the lowest priority possible. So I'll use as a priority one that puts the longest possible word first, and if there is a tie then goes with whatever word we are farthest along on. Here is an implementation.
import FlatQueue from "flatqueue";
function longest_word_from (trie, letters) {
let sorted_letters = letters.sort();
let queue = new FlatQueue();
// Entries will be [position, current_length, this_trie]
// We prioritize the longest word length first, then the
// number of characters. Since we get the minimum first,
// we make priorities negative numbers.
queue.push([0, 0, trie], - (letters.length ** 2));
while (0 < queue.length) {
let entry = queue.pop();
let position = entry[0];
let word_length = entry[1];
let this_trie = entry[2];
if (position == letters.length) {
if ('final' in this_trie) {
return this_trie['final'];
}
}
else {
if (letters[position] in this_trie) {
queue.push(
[
position + 1, // Advance the position
word_length + 1, // We added a letter
this_trie[letters[position]] // And the sub-trie after that letter
],
- letters.length * (
letters.length + position - word_length
) - word_length - 1
);
}
queue.push(
[
position + 1, // Advance the position
word_length, // We didn't add a a letter
this_trie // And stayed at the same position.
],
- letters.length * (
letters.length + position - word_length - 1
) - word_length
);
}
}
return null;
}
If the import doesn't work for you, you can simply replace that line with the code from index.js. Simply remove the leading export default and the rest will work.
And with that, here is sample code that demonstrates it in action.
let file = ['foo', 'bar', 'baz', 'floop'];
let letters = 'fleaopo'.split('')
let this_trie = {};
for (var i in file) {
add_to_trie(this_trie, file[i]);
}
console.log(longest_word_from(this_trie, letters));
If you have a long dictionary, loading the dictionary into the trie is most of your time. But once you've done that you can call it over and over again with different letters, and get answers quite quickly.

I generate 2 arrays of equal length (15), with a choice of 4 possible letters at each position - why do they come back 53% to 87% similar?

This is inspired by a Codecadamey project, where I'm learning JavaScript.
The problem is meant to simulate a simple DNA strand. It has 15 positions in the array, and those elements are either an A, T, C, or G to represent DNA bases.
There are no limits to the amount of times a single letter (base) can show up in the array.
I create 30 arrays that are made up of at least 60% C and/or G in any of the positions, these are meant to represent strong DNA strands.
I compare the strands to each other to see what % match they are. I consider a 'match' being true when there is the same base at the same position thisDNA[i] === comparisonDNA[i]
When I test a batch of 30 of these 'strong' samples to see the best and worst match levels, I find the results very tightly grouped (I ran it 3,000 times and the highest was 87%, lowest 53%), yet it is very easy for me to concieve of two samples that will survive that are a 0% match:
const sample1 = AGACCGCGCGTGGAG
const sample2 = TCTGGCGCGCACCTC
(obviously I've cheated by building these to be a 0% match and not randomly generating them)
Here's the full code: https://gist.github.com/AidaP1/0770307979e00d4e8d3c83decc0f7771
My question is as follows: Why is the grouping of matches so tight? Why do I not see anything below a 53% match after running the test thousands of times?
Full code:
// Returns a random DNA base
const returnRandBase = () => {
const dnaBases = ['A', 'T', 'C', 'G']
return dnaBases[Math.floor(Math.random() * 4)]
}
// Returns a random single stand of DNA containing 15 bases
const mockUpStrand = () => {
const newStrand = []
for (let i = 0; i < 15; i++) {
newStrand.push(returnRandBase())
}
return newStrand
}
const pAequorFactory = (num, arr) => { //factory function for new strand specimen
return {
specimenNum: num,
dna: arr,
mutate() {
//console.log(`old dna: ${this.dna}`) //checking log
let randomBaseIndex = Math.floor(Math.random() * this.dna.length) /// chooses a location to exchange the base
let newBase = returnRandBase()
while (newBase === this.dna[randomBaseIndex]) { // Rolls a new base until newBase !== current base at that position
newBase = returnRandBase()
}
this.dna[randomBaseIndex] = newBase;
//console.log(`New dna: ${this.dna}`) //checking log
return this.dna;
},
compareDNA(pAequor) { // compare two strands and output to the console
let thisDNA = this.dna;
let compDNA = pAequor.dna;
let matchCount = 0
for (i = 0; i < this.dna.length; i++) { //cycles through each array and log position + base matches on matchCount
if (thisDNA[i] === compDNA[i]) {
matchCount += 1;
};
};
let percMatch = Math.round(matchCount / this.dna.length * 100) //multiply by 100 to make 0.25 display as 25 in console log
console.log(`specimen #${this.specimenNum} and specimen #${pAequor.specimenNum} are a ${percMatch}% DNA match.`)
return percMatch;
},
compareDNAbulk(pAequor) { //as above, but does not log to console. Used for large arrays in findMostRelated()
let thisDNA = this.dna;
let compDNA = pAequor.dna;
let matchCount = 0
for (i = 0; i < this.dna.length; i++) {
if (thisDNA[i] === compDNA[i]) {
matchCount += 1;
};
};
let percMatch = Math.round(matchCount / this.dna.length * 100) //multiply by 100 to make 0.25 display as 25 in console log
return percMatch;
},
willLikelySurvive() { // looks for >= 60% of bases as either G or C
let countCG = 0;
this.dna.forEach(base => {
if (base === 'C' || base === 'G') {
countCG += 1;
}
})
//console.log(countCG) // testing
//console.log(this.dna) // testing
return countCG / this.dna.length >= 0.6
},
complementStrand() {
return this.dna.map(base => {
switch (base) {
case 'A':
return 'T';
case 'T':
return 'A';
case 'C':
return 'G';
case 'G':
return 'C';
}
})
} //close method
} // close object
} // close factory function
function generatepAequorArray(num) { // Generatess 'num' pAequor that .willLikelySurvive() = true
let pAequorArray = []; //result array
for (i = 0; pAequorArray.length < num; i++) {
let newpAequor = pAequorFactory(i, mockUpStrand()); // runs factory until there are 30 items in the result array
if (newpAequor.willLikelySurvive() === true) {
pAequorArray.push(newpAequor)
}
}
return pAequorArray;
}
function findMostRelated(array) { // champion/challenger function to find the most related specimens
let winningScore = 0;
let winner1;
let winner2;
for (let i = 0; i < array.length; i++) {
for (let j = i; j < array.length; j++) // j = i to halve the number of loops. i = 0, j = 5 is the same as i = 5, j = 0
if (i !== j) { // Do not check specimen against itself
let currentScore = array[i].compareDNAbulk(array[j]);
if (currentScore > winningScore) { // Challenger becomes the champion if they are a closer match
winningScore = currentScore;
winner1 = array[i].specimenNum;
winner2 = array[j].specimenNum;
}
}
}
let resultArray = [winner1, winner2, winningScore] // stored together for easy return
//console.log(`The most related specimens are specimen #${winner1} and specimen #${winner2}, with a ${winningScore}% match.`)
return resultArray
}
function multiArray(loops) { //test by running finding the closest match in 30 random 'will survive' samples, repaeated 1000 times. Returns the highest and lowest match across the 1000 runs
let highScore = 0;
let lowScore = 100
for (let i = 0; i < loops; i++) {
let pAequorArray = generatepAequorArray(30);
let currentArray = findMostRelated(pAequorArray);
highScore = Math.max(highScore, currentArray[2])
lowScore = Math.min(lowScore, currentArray[2])
}
return results = {
'high score': highScore,
'low score': lowScore
}
}
console.log(multiArray(10000))

Format a number to three sig figs with SI units

I would like to format an integer to 3 significant figures using SI units. For example:
1 => '1'
999 => '999'
1234 => '1.23k'
1235 => '1.24k'
The gross hack of a function I have is below, and still does not satisfy all my tests. The problems I run into involve detecting when 9… will round up to 10… and thus require one fewer decimal at the end.
tests = [[9,'9'],[1,'1'],[10,'10'],[99,'99'],[100,'100'],[999,'999'],
[1000,'1.00k'],[1004,'1.00k'],[1009,'1.01k'],[1472,'1.47k'],
[1926,'1.93k'],[1999,'2.00k'],[2000,'2.00k'],[9813,'9.81k'],
[9990,'9.99k'],[9999,'10.0k'],[10000,'10.0k'],[10010,'10.0k'],
[60712,'60.7k'],[98712,'98.7k'],[99949,'99.9k'],[99950,'100k'],
[99999,'100k'],[100000,'100k'],[400499,'400k'],[999499,'999k'],
[999500,'1.00M'],[999999,'1.00M'],[1000000,'1.00M'],
[1234567,'1.23M'],[12345678,'12.3M'],[123456789,'123M']]
tests.forEach( ([n,expected]) => {
const actual = siRound(n)
console.log(n, actual, actual==expected ? '=' : '≠', expected)
})
function siRound(x) {
if (x<1e3) return x+'';
const digits = Math.log10(x) | 0
const tier = digits/3 | 0
let str = (x / 10**(tier*3)).toFixed(2-(digits%3))
// Turn "10.00" into "10.0" and "100.0" into "100"
str = str.replace(/^(.{3})\..+|^(.{4}).+/, '$1$2')
return str + (['','k','M','G','T'])[tier]
}
Make your method recursive like. Add this, check before you return:
if (str.length>4) {
siRound(str)
}
tests = [[9,'9'],[1,'1'],[10,'10'],[99,'99'],[100,'100'],[999,'999'],
[1000,'1.00k'],[1004,'1.00k'],[1009,'1.01k'],[1472,'1.47k'],
[1926,'1.93k'],[1999,'2.00k'],[2000,'2.00k'],[9813,'9.81k'],
[9990,'9.99k'],[9999,'10.0k'],[10000,'10.0k'],[10010,'10.0k'],
[60712,'60.7k'],[98712,'98.7k'],[99949,'99.9k'],[99950,'100k'],
[99999,'100k'],[100000,'100k'],[400499,'400k'],[999499,'999k'],
[999500,'1.00M'],[999999,'1.00M'],[1000000,'1.00M'],
[1234567,'1.23M'],[12345678,'12.3M'],[123456789,'123M']]
tests.forEach( ([n,expected]) => {
const actual = siRound(n)
console.log(n, actual, actual==expected ? '=' : '≠', expected)
})
function siRound(x) {
if (x<1e3) return x+'';
const digits = Math.log10(x) | 0
const tier = digits/3 | 0
let str = (x / 10**(tier*3)).toFixed(2-(digits%3))
// Turn "10.00" into "10.0" and "100.0" into "100"
str = str.replace(/^(.{3})\..+|^(.{4}).+/, '$1$2')
if (str.length>4) { ///Add this check
siRound(str)
}
return str + (['','k','M','G','T'])[tier]
}
tests = [[9,'9'],[1,'1'],[10,'10'],[99,'99'],[100,'100'],[999,'999'],
[1000,'1.00k'],[1004,'1.00k'],[1009,'1.01k'],[1472,'1.47k'],
[1926,'1.93k'],[1999,'2.00k'],[2000,'2.00k'],[9813,'9.81k'],
[9990,'9.99k'],[9999,'10.0k'],[10000,'10.0k'],[10010,'10.0k'],
[60712,'60.7k'],[98712,'98.7k'],[99949,'99.9k'],[99950,'100k'],
[99999,'100k'],[100000,'100k'],[400499,'400k'],[999499,'999k'],
[999500,'1.00M'],[999999,'1.00M'],[1000000,'1.00M'],
[1234567,'1.23M'],[12345678,'12.3M'],[123456789,'123M']]
const siRound = x => {
if (x < 1e3) {
return x;
}
let roudedX = x;
let tier = 0;
while (roudedX >= 1000) {
roudedX /= 1000;
tier += 1;
}
roudedX = Number.parseFloat(roudedX.toPrecision(3));
if (Math.abs(roudedX - 1e3) < Number.EPSILON) {
roudedX = 1;
tier += 1;
}
return roudedX.toPrecision(3) + ['', 'k', 'M', 'G', 'T'][tier];
}
tests.forEach(([n,expected]) => {
const actual = siRound(n)
console.log(n, actual, actual==expected ? '=' : '≠', expected)
})
Based on #HereticMonkey pointing out the presence of toPrecision(), here's an answer that works, though it feels a little bit gross to me. I'll switch acceptance to a cleaner, fully-working answer if someone posts one.
// Note: intentionally returns integers below 1,000 unchanged.
// For true precision across all numbers, remove the first line.
function siRound(n, precision=3) {
if (x<1e3) return x+''
let tier = Math.log10(x)/3 | 0
let str = (x / 10**(tier*3)).toPrecision(precision)
if (str>=1e3) str = (x / 10**(++tier*3)).toPrecision(precision)
return str + (['','k','M','G','T','P','E','Z','Y'])[tier]
}

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.

Categories

Resources