How do you replace every character in a string variable without looping? - javascript

My aim is for a string passed into dna will be converted using the lookup table traslateDna and returned.
For a single character this works fine but multiple characters and empty strings breaks this.
I can get it to work running it through a loop but is there a way of not requiring a loop?
Sample dna = ACGTGGT
const traslateDna = {
'G':'C',
'C':'G',
'T':'A',
'A':'U'
}
export const toRna = (dna) => {
let rnaStr = ''
for(let i =0; i < dna.length; i++){
rnaStr+=(traslateDna[dna[i]])
}
return rnaStr;
};
Below is the closest I can come, which is pretty awful. Is there a way of using the replace()method for this.
const traslateDna = {
'G':'C',
'C':'G',
'T':'A',
'A':'U'
}
export const toRna = (dna) => {
let rnaStr = '';
rnaStr = traslateDna[dna.replace()]);
}
return rnaStr;
};

Your second example is still incorrect. You should put it into codepen and try to parse it. It should not run.
To answer your question tho, You could use recursion I suppose.
const dna = 'ACGTGGT';
const traslateDna = {
'G':'C',
'C':'G',
'T':'A',
'A':'U'
}
const toRna = (dna, offset = 0) => {
if (offset == dna.length) return dna;
let rnaStr = '';
rnaStr = dna.substring(0, offset) + traslateDna[dna[offset]] + dna.substring(offset + 1, dna.length);
return toRna(rnaStr, offset + 1);
};
console.log(toRna(dna));
Although, functionally, this method and a loop are equivilant.

Related

Dynamic masked input according to data [duplicate]

This question already has answers here:
Dynamic regex pattern in JavaScript
(4 answers)
Closed 2 years ago.
I have a response and it returns "XXX-XXX" or "XX-XXXX"
const formatUnitCode = (value, format) => {}
So basically, I want to see as formatUnitCode("123456", "XX-XXX") --> "12-3456"
I don't want to use if else because it may come in the future as XX-XX-XX
Can someone help me create this function?
I tried to do with regex but I think it is not possible to pass variable instead of {2} and {4}
const formatCode = (val) => val.replace(/(\d{2})(\d{4})/g, "$1-$2");
Is this what you would like to do?
const func = (val, first_digit) => {
let regex = new RegExp("(\\d{" + first_digit + "})(\\d{" + (6-first_digit) + "})","g");
return val.replace(regex,"$1-$2");
};
You can use simple for loop make a dynamic string format method.
const formatUnitCode = (str, format) => {
let result = '';
let j = 0;
for (let i = 0, l = format.length; i < l; i += 1) {
if (format[i] === 'X') {
result += str[j];
j += 1;
} else result += format[i];
}
for (; j < str.length; j += 1) result += str[j];
return result;
};
console.log(formatUnitCode('123456', 'XX-XXX'));
console.log(formatUnitCode('123456', 'XXX-XXX'));
console.log(formatUnitCode('123456', 'XX-XXXX'));
console.log(formatUnitCode('123456', 'XX-XX-XX'));
You can't use variables in RegExp literals, but you can when you use the RegExp() constructor to build the pattern as a string instead.
const formatStr = (val, format) => {
let ptn = format.split('-').map(part => '(.{'+part.length+'})').join('');
match = val.match(new RegExp(ptn));
match && console.log(match.slice(1).join('-'));
};
It's instructive to console.log() the ptn var to see what's happening there. We're using your arbitrary "X"-based format to derive a new, dynamic RegExp which will be used in a multi-match RegExp to grab the parts.
formatStr('123456', 'xxx-xxx'); //"123-456"
formatStr('123456', 'xx-xxxx'); //"12-3456"
This should work for any mask regardless of the letters used (you can control that behaviour by changing matcher regex). Personally, I think it's a more elastic approach than just trying to match the given mask with a regex.
const replaceWithFiller = (filler, str, matcher = /[a-zA-z]/g) => {
const arr = filler.split('');
return str.replace(matcher, () => arr.shift());
};
console.log(replaceWithFiller('123456', 'XXX-XXX')); //"123-456"
console.log(replaceWithFiller('123456', 'XX-XX-XX')); // "12-34-56"
console.log(replaceWithFiller('123456', 'XX-XXXX')); //"12-3456"
console.log(replaceWithFiller('123456', 'aa-aaaa')); // also "12-3456"
you can pass parameters to your regex using template literals:
const formatCode = (val, format) => {
const lengthFirstBlock = format.indexOf('-');
const lehgthSecondBlock = format.length - format.indexOf('-');
const regex = new RegExp(`(\\d{${lengthFirstBlock}})(\\d{${lehgthSecondBlock}})`, 'g');
return val.replace(regex, "$1-$2");
}
console.log(formatCode("123456", "XX-XXX"))
console.log(formatCode("123456", "XXX-XX"))

How do I return only the letter that repeats the most times?

How do I return only the letter that repeats the most times? How to make it return only the result e = 5 in the following case
enter code here
var s = "Teeeeessttt"
var x = (s.toLowerCase());
function count() {
array_elements = ([...x]);;
array_elements.sort();
var current = null;
var cnt = 0;
for (var i = 0; i < array_elements.length; i++) {
if (array_elements[i] != current) {
if (cnt > 0) {
document.write(current + ' - ' + cnt + '<br>');
}
current = array_elements[i];
cnt = 1;
} else {
cnt++;
}
}
if (cnt > 0) {
document.write(current + ' - ' + cnt);
}
}
count();
First you would need to count the amount of times a character occurs. You could use the reduce method to loop over each character and store that character as a key in an object. The value of the key should represent the amount of times the character has occurred.
It would look like the object below.
{
"t": 4,
"e": 5,
"s": 2
}
From here you want to look for the highest number and return the key that corresponds to it. I've borrowed the solution of this SO thread to get the highest count of the object using another reduce loop.
const string = "Teeeeessttt";
const mostOccuringCharacter = string => {
// Count the occurence of each character.
const count = [...string.toLowerCase()].reduce((counter, char) => {
counter[char] = (counter[char] || 0) + 1;
return counter;
}, {});
// Compare the values with each other and return the
// character with the highest count.
const highestChar = Object.keys(count).reduce((a, b) =>
count[a] > count[b] ? a : b);
// Return an array with the character and the count.
return [highestChar, count[highestChar]]
};
const [ char, count ] = mostOccuringCharacter(string);
console.log(`${char} = ${count}`);
#UKS points out a dupe for this, interestingly there was a post with issues with funcky unicode.. eg. πŸ‘¦πŸΏπŸ‘¦πŸ‘¦πŸΏπŸ‘¦πŸ‘¦πŸ»πŸ‘¦πŸ½πŸ‘¦πŸΎπŸ‘¦πŸΏ, but no solution was shown for this.
So with that in mind I thought I would knock up a version that handles unicode nicely. I've also split into multiple functions for re-use. As you can see it's also easy to alter to find the least used character if so wanted. Not sure if this will handle 100% unicode, there might be some even more funcky ones. :)
function unicodeStrSplit(str) {
const x = [...str];
//let handle some funcky unicode
for (let p=x.length-1;p>0;p--)
if(x[p].charCodeAt(0)===0xd83c){x[p-1] += x[p], x.splice(p, 1) };
return x;
}
function arrayCounter(arr) {
return [...arr.reduce((a,v)=>a.set(v,a.get(v)+1||1),new Map())].
sort((a,b) => b[1]-a[1]);
}
function stringCounter(str) {
return arrayCounter(unicodeStrSplit(str));
}
console.log(stringCounter("Teeeeessttt").shift()); //first array item
//funcky unicode too.
console.log(stringCounter('πŸ‘¦πŸΏπŸ‘¦πŸ‘¦πŸΏπŸ‘¦πŸ‘¦πŸ»πŸ‘¦πŸ½πŸ‘¦πŸΎπŸ‘¦πŸΏ').shift()); //first array item
//also let's get the least used
console.log(stringCounter('πŸ‘¦πŸΏπŸ‘¦πŸ‘¦πŸΏπŸ‘¦πŸ‘¦πŸ»πŸ‘¦πŸ½πŸ‘¦πŸΎπŸ‘¦πŸΏ').pop()); //last array item

What is the equivalent of C++ std::unordered_map<char, int> in Javascript?

So I am trying to map the number of times a char appears in a string. I know that in C++ it would be.
std::string str = "AbBAaaaa";
std::unordered_map<char, int> myMap;
for(auto i = str)
{
++mymap[i];
}
How would I translate this to JavaScript?
I would reduce the string into an object indexed by character. The function passed to reduce is called for each element in the input, where the first argument (the a) is the accumulator, which is either the initial value ({} here) or what the last iteration returned. The second argument (the char) is the current character being iterated over.
const str = "AbBAaaaa";
const charCounts = Array.prototype.reduce.call(str, (a, char) => {
a[char] = (a[char] || 0) + 1;
return a;
}, {});
console.log(charCounts);
You could also use
const charCounts = [...str].reduce((a, char) => // ...
which is shorter and probably a bit easier to understand at a glance, but unnecessarily creates an intermediate array from the str.
The imperative version of this, with a for loop, would look like:
const str = "AbBAaaaa";
const charCounts = {};
for (let i = 0; i < str.length; i++) {
const char = str[i];
charCounts[char] = (charCounts[char] || 0) + 1;
}
console.log(charCounts);
Javascript already has map and you can achieve same result of your C++ app as shown in this snippet
function charOccurances(str) {
var myMap = {};
if(str.length!==0){
for (let i = 0; i < str.length; i++) {
myMap[str[i]] = (myMap[str[i]] || 0) + 1;
}
}
return myMap;
}
const str = "AbABaaaa";
console.log(charOccurances(str));

javascript transform text array

I use a react component which work like this
<FontAwesomeIcon icon={faCoffee} />
it take a font awesome icon let say address-book it add fa before, delete hyphen and uppercase the first letter of each world.
address-book become faAddressBook
copyright become faCopyright
arrow-alt-circle-down become faArrowAltCircleDown
Is it possible to create a javascript function which take an array like this
["address-book","copyright","arrow-alt-circle-down"]
and transform it in an array like that
["faAddressBook","faCopyright","faArrowAltCircleDown"]
There are some ways to do it. Like using regular expression. However, your requirement is simple, so it can be easily done with JavaScript split method. Please check the following implemented function.
function formatArray(str)
{
str = str.split("-");
for (var i = 0, x = str.length; i < x; i++) {
str[i] = str[i][0].toUpperCase() + str[i].substr(1);
}
return 'fa' + str.join("");
}
var givenArr = ["address-book","copyright","arrow-alt-circle-down"];
for( var i = 0; i < givenArr.length; i++) {
givenArr[i] = formatArray(givenArr[i]);
console.log(givenArr[i]+ '\n');
}
You can do the following with Array's map() and forEach():
var arr = ["address-book","copyright","arrow-alt-circle-down"];
function upperCase(string) {
return string.charAt(0).toUpperCase() + string.slice(1);
}
var outPut = arr.map(function(item){
var temp = item.split('-');
var temp2 = [];
temp.forEach(function(data){
temp2.push(upperCase(data))
});
return 'fa' + temp2.join('')
})
console.log(outPut);
Looks like there's two essential steps here. First, we need to prepend fa onto each string, and second, we need to convert them from kebab-case to camelCase.
So just write a function for each of those conversions, then run your array through a map using each of them:
const kebabs = ["address-book","copyright","arrow-alt-circle-down"];
function kebabToCamel(str) {
return str.replace(/-(\w)/g, m => m[1].toUpperCase());
}
function prependFa(str) {
return "fa-" + str;
}
console.log(kebabs.map(prependFa).map(kebabToCamel))

Recursive parser using split in javascript

I have an algorithm where the user will enter a string and I will parse it into an array of 2+ dimensions. So, for example, the user can enter 1,2,3;4,5,6 and set the text to be parsed by the semicolon and the comma. The first pass through will create an array with 2 entries. The second pass through will create a 3 entry array in both prior spots.
The user can add or remove the number of text items to be used to parse the original string such as the semicolon or comma, meaning the resulting array can have as many dimensions as parsing items.
This doesn't seem like a difficult problem, but I have run into some snags.
Here is my code so far.
vm.parsers = [';', ','];
vm.inputString = "1,2,3,4,5;6,7,8,9,10";
function parseDatasetText( )
{
vm.real = vm.parseMe( vm.inputString, 0);
};
function parseMe( itemToParse, indexToParse )
{
if ( indexToParse < vm.parsers.length )
{
console.log('Parsing *'+itemToParse+'* with '+vm.parsers[indexToParse]);
var tempResults = itemToParse.split( vm.parsers[indexToParse] );
for (var a=0; a<tempResults.length; a++)
{
console.log('Pushing '+tempResults[a]);
tempResults[a] = vm.parseMe( tempResults[a], parseInt( indexToParse ) + 1 )
console.log('This value is '+tempResults[a]);
}
}else
{
console.log('Returning '+itemToParse);
return itemToParse
}
};
As you can see from the console logs, the algorithm spits out an undefined after the last parse, and the final answer is undefined.
Maybe I just haven't slept enough, but I was thinking that the array would recursively populate via the splits?
Thanks
function parseDatasetText(){
//composing parser from right to left into a single function
//that applies them from left to right on the data
var fn = vm.parsers.reduceRight(
(nextFn, delimiter) => v => String(v).split(delimiter).map(nextFn),
v => v
);
return fn( vm.inputString );
}
Don't know what else to add.
You can use a simple recursive function like the following (here an example with 3 different delimiters):
function multiSplit(xs, delimiters) {
if (!delimiters.length) return xs;
return xs.split(delimiters[0]).map(x => multiSplit(x, delimiters.slice(1)));
}
data = '1:10,2:20,3:30;4:40,5:50,6:60';
res = multiSplit(data, [';', ',', ':']);
console.log(res)
The following function should suit your requirements, please let me know if not
var parsers = [';', ',', ':'],
inputString = "1:a,2:b,3:c,4:d,5:e;6:f,7:g,8:h,9:i,10:j",
Result = [];
function Split(incoming) {
var temp = null;
for (var i = 0; i < parsers.length; i++)
if (incoming.indexOf(parsers[i]) >= 0) {
temp = incoming.split(parsers[i]);
break;
}
if (temp == null) return incoming;
var outgoing = [];
for (var i = 0; i < temp.length; i++)
outgoing[outgoing.length] = Split(temp[i])
return outgoing;
}
Result = Split(inputString);
try it on https://jsfiddle.net/cgy7nre1/
Edit 1 -
Added another inputString and another set of parsers: https://jsfiddle.net/cgy7nre1/1/
Did you mean this?
var inputString = "1,2,3,4,5;6,7,8,9,10";
var array=inputString.split(';');
for (var i=0;i<array.length;i++){
array[i]=array[i].split(',');
}
console.log(array);

Categories