Scan for duplicate values in a string and remove them - javascript

I am attempting to scan through and remove any duplicates from a string.
Here is an example scenario:
var str = "Z80.8, Z70.0, Z80.8";
The goal is to pass str into a function and have it returned as "Z80.8, Z70.0"
The string is separated by commas.

Use something like:
str
.split(',')
.map(function(s) { return s.trim() })
.filter(function(v, i, a) { return a.indexOf(v) === i })
.join(', ');
Split will make it an array by splitting the string at every comma.
Map will remove leading and trailing spaces.
Filter will remove any element that is already in the array.
Join will join back the array to one string.

Use regex to get each value and then use Set to remove duplicates.
const data = "Z80.8, Z70.0, Z80.8";
const res = [...new Set(data.match(/\w+\.[0-9]/g))];
console.log(res);

Javascript code splits the string on ", " then defines an anonymous function passed to filter, that takes three parameters representing the item, index and allitems. The anonymous function returns true if the index of this item is the same as the first index of that item found, otherwise false. Then join the elements of the Arrray on comma.
var str = "Z80.8, Z70.0, Z80.8";
var res = str.split(", ").filter(function(item,index,allItems){
return index == allItems.indexOf(item);
}).join(', ');
console.log(res);
Result:
Z80.8, Z70.0

Try this:
let str = "Z80.8, Z70.0, Z80.8";
str = [...new Set(str.split(", "))].join(", ");
console.log(str);

let str = "Z80.8, Z70.0, Z80.8";
let uniq = [...new Set(str.split(", "))].join(", ");

You can convert string to array using split() and then convert it to Set and then again join() it
var str = "Z80.8, Z70.0, Z80.8";
str = [... new Set(str.split(', '))].join(', ')
console.log(str);

I suggest to split this into an array then remove duplicates.
var arr = str.replace(" ", "").split(",");
var uniqueArray = arr.filter((v, i, arr) => arr.indexOf(v) === i);

Related

How to join strings in a for loop in Javascript?

I am trying to capitalise the first character of each word and join all words into one string. I have managed to capitalise the first character of each word but cant seem to get .join() to work on the final result
function generateHashtag (str) {
let split = str.split(' ')
for(let i = 0; i < split.length; i++){
let finalResult = split[i].charAt(0).toUpperCase() + split[i].substring(1)
console.log(finalResult.join(''))
}
}
console.log(generateHashtag('Hello my name is')) should return ('HelloMyNameIs')
Achieving this by split is possible. first create an array of divided strings (by the delimiter ' ') and then loop around the array and capitalize the first char using the method toUpperCase and concat the rest of the string without the first letter using slice
function generateHashtag(str) {
let split = str.split(' ');
for (let i = 0; i < split.length; i++) {
split[i] = split[i].charAt(0).toUpperCase() + split[i].slice(1);
}
return split.join('');
}
console.log(generateHashtag('Hello my name is'));
More about split - https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/split
you can do split[i] = split[i].charAt(0).toUpperCase() + split[i].substring(1) in the loop then outside loop do split.join('')
Basically you are replacing each word (split[i]) with capitalised word. Then in the end join the words.
finalResult is a String, not an Array so there is no join function.
Use this instead :
function generateHashtag (str) {
let arrayWords = str.split(' ')
const titleCasedArray = arrayWords.map(word => titleCaseWord(word))
return titleCasedArray.join('');
}
function titleCaseWord (word){
return word.slice(0,1).toUpperCase() + word.slice(1,-1).toLowerCase()
}
You can do something like this:
function generateHashtag (str) {
//returns array of strings
let split = str.split(' ')
//returns array of strings with each word capitalized
const capitalizedWordsArr = split.map( word => word.charAt(0).toUpperCase() + word.substring(1))
//returns a string by joining above array with no spaces
return capitalizedWordsArr.join('')
}
This is a perfect use-case for Array.prototype.reduce:
function generateHashtag(str) {
return str
.split(' ')
.reduce((acc, [firstLetter, ...rest]) => acc += `${firstLetter.toUpperCase()}${rest.join('')}`,
''
);
}
console.log(generateHashtag('Hello my name is')); // should return ('HelloMyNameIs')
Javascript strings are immutable so you cannot overwrite them on the go, but you can overwrite array elements.
By using String.prototype.substr() you can extract a part of the string, you can use these parts, modify it and create a new string then replace the old array element. finally returning the joined string like you wanted to
function generateHashtag(str) {
const split = str.split(' ') // array of words
for (let i = 0; i < split.length; i++)
split[i] = split[i].substr(0, 1).toUpperCase() + split[i].substr(1); // overwriting existing elements with Titlecased words
return split.join(''); // returning final string
}
console.log(generateHashtag('Hello my name is'))
You don't need to use join at all, just declare and initialize finalResult outside the loop and concatenate each word inside the loop:
function generateHashtag(str) {
const split = str.split(' '); // Array<String>
let finalResult = ''; // String
for(let i = 0; i < split.length; i++) {
const titleCased = split[i].charAt(0).toUpperCase() + split[i].substring(1);
finalResult += titleCased;
}
return finalResult;
}
console.log(generateHashtag('Hello my name is'));
However, you can simplify this code considerably by using a functional-programming (FP) style with map and reduce. See below.
I've also changed your code to use toLocaleUpperCase instead of toUpperCase and uses [0] for brevity.
It's still safe to use substring(1) for single-character strings, it just returns ''.
function generateHashtag(str) {
return ( str
.split(' ')
.map( word => word[0].toLocaleUpperCase() + word.substring(1).toLocaleLowerCase() )
.reduce( ( word, concat ) => concat + word, "" )
);
}
I forgot that join() can still be used instead of reduce (and will have an optimized implementation inside the JS engine anyway):
I've also moved the map function's logic to a named function toTitleCase.
function generateHashtag(str) {
const toTitleCase( word ) => word[0].toLocaleUpperCase() + word.substring(1).toLocaleLowerCase();
return ( str
.split(' ')
.map( word => toTitleCase( word ) ) // or just `.map( toTitleCase )`
.join()
);
}
The return statement has parens to prevent unwanted automatic-semicolon-insertion which would otherwise break the function.
If you want something similar to your code, but working, i would do this:
function generateHashtag (str) {
let split = str.split(' ')
let newStr = []
for (let i = 0; i < split.length; i++){
newStr.push(split[i].charAt(0).toUpperCase() + split[i].substring(1))
}
return newStr.join('')
}
You could also choose to do this task using a 'regular expression'.
https://cheatography.com/davechild/cheat-sheets/regular-expressions/
Here is a quick implementation:
const generateHashtag = str => {
// regular expression to capitalize the words
const regEx = /(\b[a-z](?!\s))/g
str = str.replace(regEx, (char) => {
return char.toUpperCase()
});
// remove spaces, return
return str.split(' ').join('')
}
Same code, but with less readability:
const generateHashtag = str => {
return str.replace(/(\b[a-z](?!\s))/g, (char) => {
return char.toUpperCase()
}).split(' ').join('');
}
function generateHashtag (str) {
return str.replace(/\b\S/g, e => e.toUpperCase()).replace(/\s/g,'');
}
console.log(generateHashtag('Hello my name is'))
\b: bondary \S: non space \s: space.
https://regex101.com/
//try this code solve your problem
const generateHashtag = str => {
let split = str.split(' ')
let finalResult = []
for (word of split) {
finalResult.push(word[0].toUpperCase() + word.substring(1))
}
return finalResult.join('')
}
console.log(generateHashtag('Hello my name is'))

Replace instances of an array in a string with another array

I'm working on a JS applet that requires replacement of array entries in a given string with entires from another array. This is my code as it now stands:
const string = "Lion, Unicorn, Unicorn";
const array1 = ["Lion", "Unicorn"];
const array2 = ["Fox", "Hound"];
const string2 = string.replaceAll(array1[0],array2[0]) //returns "Fox, Unicorn, Unicorn"
My desired output is :
Fox, Hound, Hound.
Specifically, I'd like to turn the contents of string2 into a function that repeats for every item in an array, but have no idea where to start.
Thanks!
Do you mean something like this?
I hope I understood the question well.
You can write a recursive function:
let string = "Lion, Unicorn, Unicorn";
let array1 = ["Lion", "Unicorn"];
let array2 = ["Fox", "Hound"];
function myCustomReplace(str, a1, a2) {
let wordToReplace=a1.shift(); // a1[0] - if array change matters
let replacementWord=a2.shift(); // a2[0] - if array change matters
if (!wordToReplace || !replacementWord) return str;
str=str.replaceAll(wordToReplace, replacementWord );
return myCustomReplace(str,a1,a2); // rturn myCustomReplace(str,a1.slice(1),a2.slice(1)) - if array change matters
}
console.log(
myCustomReplace(string,array1,array2)
)
It's sometimes worthwhile to first transform the inputs into a shape that is easier to work on. For this problem, the input sentence is better thought of as an array of words, and the two arrays used for replacement are better represented as a single object mapping input words to output words...
let string = "Lion, Unicorn, Unicorn";
let array1 = ["Lion", "Unicorn"];
let array2 = ["Fox", "Hound"];
// transform the inputs
let input = string.split(", ");
let translator = array1.reduce((acc, key, i) => {
acc[key] = array2[i];
return acc;
}, {});
// now input is ['Lion', 'Unicorn', ...]
// and transator is { 'Lion' : 'Fox', ... }
// now the problem is just a two-liner, mapping the input over the translator
let output = input.map(e => translator[e] || e)
console.log(output.join(", "))
If we use split(', ') to convert the string to an array of single words, we can use map() to replace them by searching for a pair with indexOf():
Please see comments in the code. A one-liner can be found at the end.
const string = "Lion, Unicorn, Unicorn";
const array1 = ["Lion", "Unicorn"];
const array2 = ["Fox", "Hound"];
// Split on ', '
let splitted = string.split(', ');
// Map
let result = splitted.map(w => {
// Get position in array1
const i = array1.indexOf(w);
// If we've found something
if (i !== -1) {
// Return replacement
return array2[i];
} else {
// Return original
return w;
}
});
// Create string
result = result.join(', ');
// Show
console.log(result);
// Or, as a one-liner
let result2 = string.split(', ').map(w => (array1.indexOf(w) !== -1) ? array2[array1.indexOf(w)] : w).join(', ');
console.log(result2);

Replace words in string that match word in a separate array

I am trying to add a # in front of any words in a string that match a set of 'filter' words in an array.
This is what I have so far
let wordsArray = ['she', 'smile'];
let sentence = 'She has a big smile';
let sentenceArray = sentence.split(" ");
wordsArray.forEach((i, vals) => {
sentenceArray.forEach((j, sVal) => {
if (sVal === vals) {
sentenceArray[j] = `#${j}`;
console.log(sentenceArray)
}
})
});
This is what it is spitting out in the console.
app.js:17 (5) ["She", "has", "a", "big", "smile", She: "#She"]
app.js:17 (5) ["She", "has", "a", "big", "smile", She: "#She", has:
"#has"] app.js:23 She has a big smile
Any ideas on where I am going wrong?
Repl Example
You can use Array.map to iterate through each word in the sentence, then if it matches return the word with a # symbol.
let wordsArray = ['she', 'smile'];
let sentence = 'She has a big smile';
let sentenceArray = sentence.split(" ");
sentenceArray = sentenceArray.map((word) => {
let matchIndex = wordsArray.indexOf(word.toLowerCase())
return (matchIndex !== -1)
? '#'.concat(word)
: word
})
The second parameter of the forEach callback is the index, you're currently iterating over, not the value. You should also call toLowerCase on the word in the sentence to compare against the lower-cased word in the wordsArray:
let wordsArray = ['she', 'smile'];
let sentence = 'She has a big smile';
let sentenceArray = sentence.split(" ");
wordsArray.forEach((vals) => {
sentenceArray.forEach((sVal, j) => {
if (sVal.toLowerCase() === vals) {
sentenceArray[j] = `#${sVal}`;
}
})
});
console.log(sentenceArray)
But rather than a nested loop, constructing a Set of the wordsArray would be less computationally complex (O(n) instead of O(n ^ 2)), in addition to being more elegant:
const wordsArray = ['she', 'smile'];
const wordsSet = new Set(wordsArray);
const sentence = 'She has a big smile';
const result = sentence.split(" ")
.map(word => wordsSet.has(word.toLowerCase()) ? '#' + word : word);
console.log(result);
wordsArray.forEach((word) =>sentence = sentence.replace(new RegExp(word,"ig"),"#"+word))
Iterates over all the words in teh filter then replaces the words in the sentence using a regular expression new RegExp(word, "ig") first argument is the phrase to be matched second argument "ig" is just flags, "i" ignores case sensitivity, "g" searches globally.

Sort array by custom function in JavaScript

I am using only Javascript.
I have the following string :
?pn1=age&pn2=name&pv1=12&pv2=alice
What I need to do, is have the following outcome :
age:12|name:alice
I thought of a way to do this, it is the following :
var str = "?pn1=age&pn2=name&pv1=12&pv2=alice";
var strSplit = str.split("&");
for (var i = 0; i < strSplit.length; i++) {
console.log(strSplit[i]);
}
This returns the following result :
?pn1=age
pn2=name
pv1=12
pv2=alice
Since I want to join together pn1 and pv1 and pn2 and pv2, the number present in the end of the string is important.
?pn1=age
pn2=name
pv1=12
pv2=alice
So I thought a way to do this is to sort the array by this number. and then joining every 2 values together after sorting.
I tried the following code :
strSplit.sort(function() {
var pref = strSplit[i].split('=')[0];
return pref.charAt(pref.length-1);
});
It does not seem to work
Any help would be appreciated
You could split the parts, collect all items and return a joined string.
var string = '?pn1=age&pn2=name&pv1=12&pv2=alice',
result = string
.slice(1)
.split('&')
.reduce((r, p) => {
var [k, value] = p.split('='),
[key, index] = k.split(/(\d+)/);
index--;
r[index] = r[index] || {};
r[index][key] = value;
return r;
}, [])
.map(({ pn, pv }) => [pn, pv].join(':'))
.join('|');
console.log(result);
You can do that in following steps.
You can loop through half of the array and add corresponding keys and values to an array.
Consider i is the current index when we loop through half array.
The element at position i will be key.
Add the half of the length and add it to i to get corresponding value.
split() both key and value by = and get the second element.
var str = "?pn1=age&pn2=name&pv1=12&pv2=alice";
var arr = str.split("&");
let half = arr.length/2
let res = [];
for (var i = 0; i < half; i++) {
res.push(`${arr[i].split('=')[1]}:${arr[i + half].split('=')[1]}`);
}
console.log(res.join('|'))
You could use URLSearchParams to convert the query string to a collection of key-value pair.
Then loop through them to group the the pv and pn values based on the number.
Separate the string and and number values using the regex: (\D+)(\d+)
Loop through the obj.pn and get the corresponding pv value for the same number
Join the resulting array with |
This works with pn and pv values in any random order
const searchParams = new URLSearchParams("?pn1=age&pn2=name&pv1=12&pv2=alice")
const obj = { pn: {}, pv: {} }
for (let [key, value] of searchParams) {
const [, k, number] = key.match(/(\D+)(\d+)/)
obj[k][number] = value
}
const output = Object.entries(obj.pn)
.map(([n, key]) => `${key}:${obj.pv[n]}`)
.join("|")
console.log(output)
One idea is to first split values on & and add it to take digit as key and place on object and then later place the respective values in desired format
var str = "?pn1=age&pn2=name&pv1=12&pv2=alice".replace(/^\?/,'')
var strSplit = str.split("&");
let op = strSplit.reduce((op,inp) => {
let [key,value] = inp.split('=')
let digit = key.match(/\d+/)[0]
op[digit] = op[digit] || []
op[digit].push(value)
return op
},{})
let final = Object.values(op).reduce((op,inp) => {
let [key,value] = inp
op.push(`${key}:${value}`)
return op
} ,[]).join(' | ')
console.log(final)
You could convert that & split to a string and remove the ?xxx= then split it again by , to finally have an array with the stuff you're looking at.
var str = "?pn1=age&pn2=name&pv1=12&pv2=alice";
var split = str.split('&').toString().replace(/([?]?[pnv0-9]+[=])/g,'').split(',');
console.log(split[0] + ':' + split[2] + '|' + split[1] + ':' + split[3]);
EDIT : worth mentioning for those who are looking to the best performing solution, I tested all those provided here, click here for more infos.
The solution's list from the fastest to the slowest :
Maheer Ali (113,610 ops/s ±1.48% fastest)
tcj (112,324 ops/s ±1.01% 1.13% slower)
Nina Scholz (81,067 ops/s ±1.81% 28.64% slower)
Code Maniac (80,074 ops/s ±0.99% 29.52% slower)
adiga (33,065 ops/s ±0.92% 70.9% slower)

Regex for creating an array from String

I have a string as follows
var str = "[series-3,series-5,series-6],[a3,a4,a5],[class a,class b]";
I want to get three arrays from above string as follows
var arr1 = ["series-3","series-5","series-6"];
var arr2 = ["a3","a4","a5"];
var arr3 = ["class a", "class b"];
What regex should I use to achieve this?
Can this be done without regex?
Use String#split() method
var str = "[series-3,series-5,series-6],[a3,a4,a5],[class a,class b]";
// split string based on comma followed by [
var temp = str.split(/,(?=\[)/);
// remove [ and ] from string usning slice
// then split using , to get the result array
var arr1 = temp[0].slice(1, -1).split(',');
var arr2 = temp[1].slice(1, -1).split(',');
var arr3 = temp[2].slice(1, -1).split(',');
console.log(arr1, arr2, arr3);
Or same method with some variation
var str = "[series-3,series-5,series-6],[a3,a4,a5],[class a,class b]";
// Remove [ at start and ] at end using slice
// and then split string based on `],[`
var temp = str.slice(1, -1).split('],[');
// then split using , to get the result array
var arr1 = temp[0].split(',');
var arr2 = temp[1].split(',');
var arr3 = temp[2].split(',');
console.log(arr1, arr2, arr3);
RegEx and String methods can be used. It's better to create an object and store individual arrays inside that object.
var str = "[series-3,series-5,series-6],[a3,a4,a5],[class a,class b]";
// Match anything that is inside the `[` and `]`
var stringsArr = str.match(/\[[^[\]]*\]/g);
// Result object
var result = {};
// Iterate over strings inside `[` and `]` and split by the `,`
stringsArr.forEach(function(str, i) {
result['array' + (i + 1)] = str.substr(1, str.length - 2).split(',');
});
console.log(result);
var str = "[series-3,series-5,series-6],[a3,a4,a5],[class a,class b]";
var stringsArr = str.match(/\[[^[\]]*\]/g);
var result = {};
stringsArr.forEach(function(str, i) {
result['array' + (i + 1)] = str.substr(1, str.length - 2).split(',');
});
console.log(result);
To create the global variables(Not recommended), just remove var result = {}; and replace result by window in the forEach.
I would prefer to do it like this
var str = "[series-3,series-5,series-6],[a3,a4,a5],[class a,class b]",
arrs = str.match(/[^[]+(?=])/g).map(s => s.split(","));
console.log(arrs);
Just for the fun of it, another way where we add the missing quotes and use JSON.parse to convert it to a multidimensional array.
var str = "[series-3,series-5,series-6],[a3,a4,a5],[class a,class b]";
var result = JSON.parse("[" + str.replace(/\[/g,'["').replace(/\]/g,'"]').replace(/([^\]]),/g,'$1","') + "]");
console.log(result[0]);
console.log(result[1]);
console.log(result[2]);

Categories