Related
I'm trying to compare two strings to see if they are anagrams.
My problem is that I'm only comparing the first letter in each string. For example, "Mary" and "Army" will return true but unfortunately so will "Mary" and Arms."
How can I compare each letter of both strings before returning true/false?
Here's a jsbin demo (click the "Console" tab to see the results"):
http://jsbin.com/hasofodi/1/edit
function compare (a, b) {
y = a.split("").sort();
z = b.split("").sort();
for (i=0; i<y.length; i++) {
if(y.length===z.length) {
if (y[i]===z[i]){
console.log(a + " and " + b + " are anagrams!");
break;
}
else {
console.log(a + " and " + b + " are not anagrams.");
break;
}
}
else {
console.log(a + " has a different amount of letters than " + b);
}
break;
}
}
compare("mary", "arms");
Instead of comparing letter by letter, after sorting you can join the arrays to strings again, and let the browser do the comparison:
function compare (a, b) {
var y = a.split("").sort().join(""),
z = b.split("").sort().join("");
console.log(z === y
? a + " and " + b + " are anagrams!"
: a + " and " + b + " are not anagrams."
);
}
If you want to write a function, without using inbuilt one, Check the below solution.
function isAnagram(str1, str2) {
if(str1 === str2) {
return true;
}
let srt1Length = str1.length;
let srt2Length = str2.length;
if(srt1Length !== srt2Length) {
return false;
}
var counts = {};
for(let i = 0; i < srt1Length; i++) {
let index = str1.charCodeAt(i)-97;
counts[index] = (counts[index] || 0) + 1;
}
for(let j = 0; j < srt2Length; j++) {
let index = str2.charCodeAt(j)-97;
if (!counts[index]) {
return false;
}
counts[index]--;
}
return true;
}
This considers case sensitivity and removes white spaces AND ignore all non-alphanumeric characters
function compare(a,b) {
var c = a.replace(/\W+/g, '').toLowerCase().split("").sort().join("");
var d = b.replace(/\W+/g, '').toLowerCase().split("").sort().join("");
return (c ===d) ? "Anagram":"Not anagram";
}
Quick one-liner solution with javascript functions - toLowerCase(), split(), sort() and join():
Convert input string to lowercase
Make array of the string with split()
Sort the array alphabetically
Now join the sorted array into a string using join()
Do the above steps to both strings and if after sorting strings are the same then it will be anargam.
// Return true if two strings are anagram else return false
function Compare(str1, str2){
if (str1.length !== str2.length) {
return false
}
return str1.toLowerCase().split("").sort().join("") === str2.toLowerCase().split("").sort().join("")
}
console.log(Compare("Listen", "Silent")) //true
console.log(Compare("Mary", "arms")) //false
No need for sorting, splitting, or joining. The following two options are efficient ways to go:
//using char array for fast lookups
const Anagrams1 = (str1 = '', str2 = '') => {
if (str1.length !== str2.length) {
return false;
}
if (str1 === str2) {
return true;
}
const charCount = [];
let startIndex = str1.charCodeAt(0);
for (let i = 0; i < str1.length; i++) {
const charInt1 = str1.charCodeAt(i);
const charInt2 = str2.charCodeAt(i);
startIndex = Math.min(charInt1, charInt2);
charCount[charInt1] = (charCount[charInt1] || 0) + 1;
charCount[charInt2] = (charCount[charInt2] || 0) - 1;
}
while (charCount.length >= startIndex) {
if (charCount.pop()) {
return false;
}
}
return true;
}
console.log(Anagrams1('afc','acf'))//true
console.log(Anagrams1('baaa','bbaa'))//false
console.log(Anagrams1('banana','bananas'))//false
console.log(Anagrams1('',' '))//false
console.log(Anagrams1(9,'hey'))//false
//using {} for fast lookups
function Anagrams(str1 = '', str2 = '') {
if (str1.length !== str2.length) {
return false;
}
if (str1 === str2) {
return true;
}
const lookup = {};
for (let i = 0; i < str1.length; i++) {
const char1 = str1[i];
const char2 = str2[i];
const remainingChars = str1.length - (i + 1);
lookup[char1] = (lookup[char1] || 0) + 1;
lookup[char2] = (lookup[char2] || 0) - 1;
if (lookup[char1] > remainingChars || lookup[char2] > remainingChars) {
return false;
}
}
for (let i = 0; i < str1.length; i++) {
if (lookup[str1[i]] !== 0 || lookup[str2[i]] !== 0) {
return false;
}
}
return true;
}
console.log(Anagrams('abc', 'cba'));//true
console.log(Anagrams('abcc', 'cbaa')); //false
console.log(Anagrams('abc', 'cde')); //false
console.log(Anagrams('aaaaaaaabbbbbb','bbbbbbbbbaaaaa'));//false
console.log(Anagrams('banana', 'ananab'));//true
Cleanest and most efficient solution for me
function compare(word1, word2) {
const { length } = word1
if (length !== word2.length) {
return false
}
const charCounts = {}
for (let i = 0; i < length; i++) {
const char1 = word1[i]
const char2 = word2[i]
charCounts[char1] = (charCounts[char1] || 0) + 1
charCounts[char2] = (charCounts[char2] || 0) - 1
}
for (const char in charCounts) {
if (charCounts[char]) {
return false
}
}
return true
}
I modified your function to work.
It will loop through each letter of both words UNTIL a letter doesn't match (then it knows that they AREN'T anagrams).
It will only work for words that have the same number of letters and that are perfect anagrams.
function compare (a, b) {
y = a.split("").sort();
z = b.split("").sort();
areAnagrams = true;
for (i=0; i<y.length && areAnagrams; i++) {
console.log(i);
if(y.length===z.length) {
if (y[i]===z[i]){
// good for now
console.log('up to now it matches');
} else {
// a letter differs
console.log('a letter differs');
areAnagrams = false;
}
}
else {
console.log(a + " has a different amount of letters than " + b);
areAnagrams = false;
}
}
if (areAnagrams) {
console.log('They ARE anagrams');
} else {
console.log('They are NOT anagrams');
}
return areAnagrams;
}
compare("mary", "arms");
A more modern solution without sorting.
function(s, t) {
if(s === t) return true
if(s.length !== t.length) return false
let count = {}
for(let letter of s)
count[letter] = (count[letter] || 0) + 1
for(let letter of t) {
if(!count[letter]) return false
else --count[letter]
}
return true;
}
function validAnagramOrNot(a, b) {
if (a.length !== b.length)
return false;
const lookup = {};
for (let i = 0; i < a.length; i++) {
let character = a[i];
lookup[character] = (lookup[character] || 0) + 1;
}
for (let i = 0; i < b.length; i++) {
let character = b[i];
if (!lookup[character]) {
return false;
} else {
lookup[character]--;
}
}
return true;
}
validAnagramOrNot("a", "b"); // false
validAnagramOrNot("aza", "zaa"); //true
Here's my contribution, I had to do this exercise for a class! I'm finally understanding how JS works, and as I was able to came up with a solution (it's not - by far - the best one, but it's ok!) I'm very happy I can share this one here, too! (although there are plenty solutions here already, but whatever :P )
function isAnagram(string1, string2) {
// first check: if the lenghts are different, not an anagram
if (string1.length != string2.length)
return false
else {
// it doesn't matter if the letters are capitalized,
// so the toLowerCase method ensures that...
string1 = string1.toLowerCase()
string2 = string2.toLowerCase()
// for each letter in the string (I could've used for each :P)
for (let i = 0; i < string1.length; i++) {
// check, for each char in string2, if they are NOT somewhere at string1
if (!string1.includes(string2.charAt(i))) {
return false
}
else {
// if all the chars are covered
// and the condition is the opposite of the previous if
if (i == (string1.length - 1))
return true
}
}
}
}
First of all, you can do the length check before the for loop, no need to do it for each character...
Also, "break" breaks the whole for loop. If you use "continue" instead of "break", it skips the current step.
That is why only the first letters are compared, after the first one it quits the for loop.
I hope this helps you.
function compare (a, b) {
y = a.split("").sort();
z = b.split("").sort();
if(y.length==z.length) {
for (i=0; i<y.length; i++) {
if (y[i]!==z[i]){
console.log(a + " and " + b + " are not anagrams!");
return false;
}
}
return true;
} else { return false;}}
compare("mary", "arms");
Make the function return false if the length between words differ and if it finds a character between the words that doesn't match.
// check if two strings are anagrams
var areAnagrams = function(a, b) {
// if length is not the same the words can't be anagrams
if (a.length != b.length) return false;
// make words comparable
a = a.split("").sort().join("");
b = b.split("").sort().join("");
// check if each character match before proceeding
for (var i = 0; i < a.length; i++) {
if ((a.charAt(i)) != (b.charAt(i))) {
return false;
}
}
// all characters match!
return true;
};
It is specially effective when one is iterating through a big dictionary array, as it compares the first letter of each "normalised" word before proceeding to compare the second letter - and so on. If one letter doesn't match, it jumps to the next word, saving a lot of time.
In a dictionary with 1140 words (not all anagrams), the whole check was done 70% faster than if using the method in the currently accepted answer.
an anagram with modern javascript that can be use in nodejs. This will take into consideration empty strings, whitespace and case-sensitivity. Basically takes an array or a single string as input. It relies on sorting the input string and then looping over the list of words and doing the same and then comparing the strings to each other. It's very efficient. A more efficient solution may be to create a trie data structure and then traversing each string in the list. looping over the two words to compare strings is slower than using the built-in string equality check.
The function does not allow the same word as the input to be considered an anagram, as it is not an anagram. ;) useful edge-case.
const input = 'alerting';
const list1 = 'triangle';
const list2 = ['', ' ', 'alerting', 'buster', 'integral', 'relating', 'no', 'fellas', 'triangle', 'chucking'];
const isAnagram = ((input, list) => {
if (typeof list === 'string') {
list = [list];
}
const anagrams = [];
const sortedInput = sortWord(input).toLowerCase();
const inputLength = sortedInput.length;
list.forEach((element, i) => {
if ( inputLength === element.length && input !== element ) {
const sortedElement = sortWord(element).toLowerCase();
if ( sortedInput === sortedElement) {
anagrams.push(element);
}
}
});
return anagrams;
})
const sortWord = ((word) => {
return word.split('').sort().join('');
});
console.log(`anagrams for ${input} are: ${isAnagram(input, list1)}.`);
console.log(`anagrams for ${input} are: ${isAnagram(input, list2)}.`);
Here is a simple algorithm:
1. Remove all unnecessary characters
2. make objects of each character
3. check to see if object length matches and character count matches - then return true
const stripChar = (str) =>
{
return str.replace(/[\W]/g,'').toLowerCase();
}
const charMap = str => {
let MAP = {};
for (let char of stripChar(str)) {
!MAP[char] ? (MAP[char] = 1) : MAP[char]++;
}
return MAP;
};
const anagram = (str1, str2) => {
if(Object.keys(charMap(str1)).length!==Object.keys(charMap(str2)).length) return false;
for(let char in charMap(str1))
{
if(charMap(str1)[char]!==charMap(str2)[char]) return false;
}
return true;
};
console.log(anagram("rail safety","!f%airy tales"));
I think this is quite easy and simple.
function checkAnagrams(str1, str2){
var newstr1 = str1.toLowerCase().split('').sort().join();
var newstr2 = str2.toLowerCase().split('').sort().join();
if(newstr1 == newstr2){
console.log("String is Anagrams");
}
else{
console.log("String is Not Anagrams");
}
}
checkAnagrams("Hello", "lolHe");
checkAnagrams("Indian", "nIndisn");
//The best code so far that checks, white space, non alphabets
//characters
//without sorting
function anagram(stringOne,stringTwo){
var newStringOne = ""
var newStringTwo = ''
for(var i=0; i<stringTwo.length; i++){
if(stringTwo[i]!= ' ' && isNaN(stringTwo[i]) == true){
newStringTwo = newStringTwo+stringTwo[i]
}
}
for(var i=0; i<stringOne.length; i++){
if(newStringTwo.toLowerCase().includes(stringOne[i].toLowerCase())){
newStringOne=newStringOne+stringOne[i].toLowerCase()
}
}
console.log(newStringOne.length, newStringTwo.length)
if(newStringOne.length==newStringTwo.length){
console.log("Anagram is === to TRUE")
}
else{console.log("Anagram is === to FALSE")}
}
anagram('ddffTTh####$', '#dfT9t#D##H$F')
function anagrams(str1,str2){
//spliting string into array
let arr1 = str1.split("");
let arr2 = str2.split("");
//verifying array lengths
if(arr1.length !== arr2.length){
return false;
}
//creating objects
let frqcounter1={};
let frqcounter2 ={};
// looping through array elements and keeping count
for(let val of arr1){
frqcounter1[val] =(frqcounter1[val] || 0) + 1;
}
for(let val of arr2){
frqcounter2[val] =(frqcounter2[val] || 0) + 1;
}
console.log(frqcounter1);
console.log(frqcounter2);
//loop for every key in first object
for(let key in frqcounter1){
//if second object does not contain same frq count
if(frqcounter2[key] !== frqcounter1[key]){
return false;
}
}
return true;
}
anagrams('anagrams','nagramas');
The fastest Algorithm
const isAnagram = (str1, str2) => {
if (str1.length !== str2.length) {
return false
}
const obj = {}
for (let i = 0; i < str1.length; i++) {
const letter = str1[i]
obj[letter] ? obj[letter] += 1 : obj[letter] = 1
}
for (let i = 0; i < str2.length; i++) {
const letter = str2[i]
if (!obj[letter]) {
return false
}
else {
obj[letter] -= 1
}
}
return true
}
console.log(isAnagram('lalalalalalalalala', 'laalallalalalalala'))
console.time('1')
isAnagram('lalalalalalalalala', 'laalallalalalalala') // about 0.050ms
console.timeEnd('1')
const anagram = (strA, strB) => {
const buildAnagram = (str) => {
const charObj = {};
for(let char of str.replace(/[^\w]/g).toLowerCase()) {
charObj[char] = charObj[char] + 1 || 1;
}
return charObj;
};
const strObjAnagramA = buildAnagram(strA);
const strObjAnagramB = buildAnagram(strB);
if(Object.keys(strObjAnagramA).length !== Object.keys(strObjAnagramB).length) {
console.log(strA + ' and ' + strB + ' is not an anagram');
return false;
}
for(let char in strObjAnagramA) {
if(strObjAnagramA[char] !== strObjAnagramB[char]) {
console.log(strA + ' and ' + strB + ' is not an anagram');
return false;
}
}
return true; } //console.log(anagram('Mary','Arms')); - false
Similar approach with filter function
const str1 = 'triangde'
const str2 = 'integral'
const st1 = str1.split('')
const st2 = str2.split('')
const item = st1.filter((v)=>!st2.includes(v))
const result = item.length === 0 ? 'Anagram' : 'Not anagram' + ' Difference - ' + item;
console.log(result)
I want to write a function to compress the characters of a string such as 'bbbab' would be converted to 'b3ab' and I'm getting stuck
it's only printing "b3"
here's the code so far
let string = 'bbbab';
let letters = string.split("");
let currentAlphabetLetter = letters[0];
let count = 0;
let newString = [];
string.split("").forEach(letter => {
if (letter === currentAlphabetLetter) {
count++;
} else {
if (count > 0) {
newString.push(`${currentAlphabetLetter}${count}`);
} else {
newString.push(`${letter}`);
}
count = 0;
currentAlphabetLetter = letter;
}
})
console.log(newString);
When you start a new letter, you need to set count to 1, otherwise you're not counting the first occurrence of the character.
This isn't a problem at the very beginning of the string, because you process the first letter twice: you extract it with let currentAlphabetLetter = letters[0]; and then process it again on the first iteration of the forEach. To make the beginning of the string the same as other occurrences, you should iterate over the substring starting with the 2nd character.
And rather than pushing onto an array, you should append to a string.
When count is 1 you need to append currentAlphabetLetter, not letter.
let string = 'bbbab';
let letters = string.split("");
let currentAlphabetLetter = letters[0];
let count = 1;
let newString = "";
string.substr(1).split("").forEach(letter => {
if (letter === currentAlphabetLetter) {
count++;
} else {
if (count > 1) {
newString += `${currentAlphabetLetter}${count}`;
} else {
newString += `${currentAlphabetLetter}`;
}
count = 1;
currentAlphabetLetter = letter;
}
});
// Process the last letter
if (count > 1) {
newString += `${currentAlphabetLetter}${count}`;
} else {
newString += `${currentAlphabetLetter}`;
}
console.log(newString);
You may do as follows;
var str = 'bbbabccc',
res = [...str].reduce((r,c,i) => (r[r.length-1][0] === c || !i) ? (r[r.length-1] += c, r)
: r.concat(c), [""])
.reduce((r,s) => r + s[0] + (s.length-1 ? s.length : ""), "");
console.log(res);
We have two .reduce()s cascaded here but first it's good to know that [...str] turns into ["b", "b", "b", "a", "b", "c", "c", "c"].
The first .reduce() will reduce it to an array of strings such as ["bbb", "a", "b", "ccc"].
The second .reduce() will further reduce it to the result. The inner mechanics of each reducers are for you to solve.
However, as hint, keep in mind that the comma operator , as in (r[r.length-1] += c, r) takes the last element of r array (accumulator here) adds c to the end of it and returns r.
Like this should work for you
let string = 'bbbab';
let newString = [];
if (string.length < 2) { console.log(string); }
else {
let letters = string.split("");
let prev = letters[0];
let count = 1;
for( var i = 1; i < letters.length; i++) {
if (letters[i] !== prev) {
count > 1 ? newString.push(`${prev}${count}`) : newString.push(`${prev}`);
count = 1;
} else {
count++;
}
prev = letters[i];
}
/* last element push */
count > 1 ? newString.push(`${prev}${count}`) : newString.push(`${prev}`);
console.log(newString.join(""));
}
This looked fairly straightforward to me when I started, but for some reason I'm getting an empty array everytime I try to run the result on codewars. I'm hoping you can help me identify what the problem is.
function alphabetPosition(text) {
text.split(' ').join('');
var chari = "";
var arr = [];
var alphabet = "abcdefghijklmnopqrstuvwxyz".split('');
for(var i = 0; i < text.len; i++){
chari = text.charAt(i).toLowerCase();
if(alphabet.indexOf(chari) > -1){
arr.push(alphabet.indexOf(chari));
}
}
return arr;
}
console.log(alphabetPosition("Hello World"));
My idea is to get the text from the parameter then strip out the spaces. I made a variable for my empty array and make an alphabet string that I can later search through. In the for loop, i make each character lowercase, and if the character is found in the alphabet string, its position gets pushed into the array (arr). I appreciate your time.
The Kata works with this code. Try with this one:
function alphabetPosition(text) {
var result = "";
for (var i = 0; i < text.length; i++) {
var code = text.toUpperCase().charCodeAt(i)
if (code > 64 && code < 91) result += (code - 64) + " ";
}
return result.slice(0, result.length - 1);
}
console.log(alphabetPosition("The sunset sets at twelve o' clock."));
You need the String#length property
text.length
instead of text.len.
function alphabetPosition(text) {
var chari,
arr = [],
alphabet = "abcdefghijklmnopqrstuvwxyz",
i;
for (var i = 0; i < text.length; i++){
chari = text[i].toLowerCase();
if (alphabet.indexOf(chari) !== -1){
arr.push(alphabet.indexOf(chari));
}
}
return arr;
}
console.log(alphabetPosition("Hello World!!1"));
A solution with ES6
function alphabetPosition(text) {
return [...text].map(a => parseInt(a, 36) - 10).filter(a => a >= 0);
}
console.log(alphabetPosition("Hello World!!1"));
First : deleting space
Second : mapping each char with its alphabet rank
Third : test with the string Happy new year
var alphabet = "abcdefghijklmnopqrstuvwxyz".split('');
var alphabetPosition = text =>
text.split('').map(x => alphabet.indexOf(x) + 1);
console.log(alphabetPosition("happy new year"));
function alphabetPosition(text) {
const words = text.toLowerCase().replace(/[^a-z]/g,"");
return [...words].map(v=> v.charCodeAt() - 96);
}
First we take the text and transform it into lowercase to get rid of the capital letters using text.toLowerCase() and then we do .replace(/[^a-z]/g,"") to replace all the non a-z characters with nothing.
The next step is to spread the string out into an array using [...words] and then mapping it to get the ascii character code of each a-z character.
Since a = 97 and b = 98 etc we will subtract 96 so that we get a = 1 and b = 2 etc (the position of the letters in the alphabet)
You can make it even easier, by making use of the acii code. Because a = ascii code 97, b = 98 etc. And there is a javascript function String.charCodeAt( n ) which returns the ascii code at a specific function. You only have to alter the offset for capitals (if you want to support them).
function alphabetPosition( text ) {
var positions = [];
for ( var i = 0; i < text.length; i++ ) {
var charCode = text.charCodeAt( i );
if ( charCode >= 97 && charCode <= 122 ) {
positions.push( charCode - 96 );
} else if ( charCode >= 65 && charCode <= 90 ) { // get rid of this if you don't care about capitals
positions.push( charCode - 64 );
}
}
return positions;
}
var positions = alphabetPosition( 'Hello World' );
console.log(positions);
Checkout this working fiddle
This example will return based on a 0 based array, and uses lambda expressions with filter. I recycle the original byte array created by splitting the text passed to the method.
function alphabetPosition(text) {
var bytes = text.split('');
var alphabet = "abcdefghijklmnopqrstuvwxyz".split('');
for (var i = 0, len = text.length; i < len; i++) {
bytes[i] = alphabet.indexOf(bytes[i].toLowerCase());
}
return bytes.filter(n => { if(n > -1) return n; } ).join(' ');
}
console.log(alphabetPosition("Hello World"));
For a 1 based array result Kata Codewars Friendly
function alphabetPosition(text) {
var bytes = text.split('');
var alphabet = "abcdefghijklmnopqrstuvwxyz".split('');
for (var i = 0, len = text.length; i < len; i++) {
bytes[i] = alphabet.indexOf(bytes[i].toLowerCase()) + 1;
}
return bytes.filter(n => { if(n > 0) return n; } ).join(' ');
}
console.log(alphabetPosition("Hello World"));
You can also use .charCodeAt function:
function alphabetPosition(text) {
start = "a".charCodeAt(0);
end = "z".charCodeAt(0);
res = [];
for (var i = 0; i < text.length; i++) {
index = text.charAt(i).toLowerCase().charCodeAt(0);
if (index >= start && index <= end) {
res.push(index - start +1); // +1 assuming a is 1 instead of 0
} else {
res.push(0); // Or do w/e you like with non-characters
}
}
return res;
}
console.log(alphabetPosition("Hello World"));
You may do something like this;
var alpha = [].reduce.call("abcdefghijklmnopqrstuvwxyz0123456789 .,!",(p,c,i) => (p[c] = i,p),{}),
str = "Happy 2017 whatever..!",
coded = [].map.call(str, c => alpha[c.toLowerCase()]);
console.log(coded);
change len to length:
(var i = 0; i < text.len; i++)
// change to
(var i = 0; i < text.length; i++)
Here is a much shorter version that does the same:
function alphabetPosition(text){
return text.split('').map(function(character){ return character.charCodeAt(0) - 'a'.charCodeAt(0) + 1; })
}
console.log(alphabetPosition("Hello World"));
This was my solution on CodeWars. Works perfectly ;)
let alphabetPosition = (text) => {
let str = Array.from(text.toLowerCase().replace(/[^a-z]/g,''));
let arr = [];
for (let i = 0; i < str.length; i++) {
arr.push(str[i].charCodeAt() - 96);
}
return arr.join(' ');
}
my answer
function alphabetPosition(text) {
if (text.match(/[a-z]/gi)) { // if text is not emtpty
let justAlphabet = text.match(/[a-z]/gi).join("").toLowerCase(); //first extract characters other than letters
let alphabet = "abcdefghijklmnopqrstuvwxyz";
let a = []; // Create an empty array
for (let i = 0; i < justAlphabet.length; i++) {
a.push(alphabet.indexOf(justAlphabet[i]) + 1); //and characters index number push in this array
}
return a.join(" ");
} else {
return "";
}
}
console.log(alphabetPosition("The sunset sets at twelve o' clock."));
this one should work
const lineNumberHandler = (arr) => {
const alphabet = 'abcdefghijklmnopqrstuwxyz';
return arr.map((el) => `${alphabet.indexOf(el) + 1}:${el}`);
}
This may solve the issue too:
function alphabetPosition(text) {
const alphabet = 'abcdefghijklmnopqrstuvwxyz'
const textWithoutSpaces = text.replace(/\s/g, '');
const numbers = Array.from(textWithoutSpaces).map((letter) => {
const lowerCaseLetter = letter.toLowerCase();
const charI = alphabet.indexOf(lowerCaseLetter)+1
if(charI) return charI
return null
})
const withoutEmptyValues = numbers.filter(Boolean)
return withoutEmptyValues.join(' ')
}
function alphabetPosition(text) {
const letters = text.split('')
const result = letters.map((l, ix) => {
const code = l.toUpperCase().charCodeAt() - 64
if (l.length && code > 0 && code <= 26) {
return code
}
})
return result.join(' ').replace(/\s+/g, ' ').trim()
}
I like to do "Single Line Responsibility", so in every line you can find only one action.
The return line, delete all multiples spaces.
An optimized version of it.
function alphabetPosition(text) {
let split = text.split("");
split = split.filter((el) => /^[a-zA-Z]+$/.test(el));
let str = "";
split.forEach(
(el) => (str += el.toLowerCase().charCodeAt(0) - "96" + " ")
);
return str.trim();
}
console.log(alphabetPosition("The sunset sets at twelve o' clock."));
function alphaPosition(test){
//the object assigns the position value to every alphabet property
const lookupAlph = {a:1,b:2,c:3,d:4,e:5,f:6,g:7,h:8,i:9,j:10,k:11,l:12,m:13,n:14,o:15,p:16,q:17,r:18,s:19,t:20,u:21,v:22,w:23,x:24,y:25,z:26}
//converts our text first to lowercase, then removes every non-alphabet
// it proceeds to covert the text to an array,
// then we use the map method to convert it to its position in the alphabet
// the last thing we do is convert our array back to a string using the join method
const alphaPosition = text.toLowerCase()
.replace(/[^a-z]/g, "")
.split("")
.map((a) => lookupAlph[a])
.join(" ")
return alphaPosition;
}
I have a string with repeated letters. I want letters that are repeated more than once to show only once.
Example input: aaabbbccc
Expected output: abc
I've tried to create the code myself, but so far my function has the following problems:
if the letter doesn't repeat, it's not shown (it should be)
if it's repeated once, it's show only once (i.e. aa shows a - correct)
if it's repeated twice, shows all (i.e. aaa shows aaa - should be a)
if it's repeated 3 times, it shows 6 (if aaaa it shows aaaaaa - should be a)
function unique_char(string) {
var unique = '';
var count = 0;
for (var i = 0; i < string.length; i++) {
for (var j = i+1; j < string.length; j++) {
if (string[i] == string[j]) {
count++;
unique += string[i];
}
}
}
return unique;
}
document.write(unique_char('aaabbbccc'));
The function must be with loop inside a loop; that's why the second for is inside the first.
Fill a Set with the characters and concatenate its unique entries:
function unique(str) {
return String.prototype.concat.call(...new Set(str));
}
console.log(unique('abc')); // "abc"
console.log(unique('abcabc')); // "abc"
Convert it to an array first, then use Josh Mc’s answer at How to get unique values in an array, and rejoin, like so:
var nonUnique = "ababdefegg";
var unique = Array.from(nonUnique).filter(function(item, i, ar){ return ar.indexOf(item) === i; }).join('');
All in one line. :-)
Too late may be but still my version of answer to this post:
function extractUniqCharacters(str){
var temp = {};
for(var oindex=0;oindex<str.length;oindex++){
temp[str.charAt(oindex)] = 0; //Assign any value
}
return Object.keys(temp).join("");
}
You can use a regular expression with a custom replacement function:
function unique_char(string) {
return string.replace(/(.)\1*/g, function(sequence, char) {
if (sequence.length == 1) // if the letter doesn't repeat
return ""; // its not shown
if (sequence.length == 2) // if its repeated once
return char; // its show only once (if aa shows a)
if (sequence.length == 3) // if its repeated twice
return sequence; // shows all(if aaa shows aaa)
if (sequence.length == 4) // if its repeated 3 times
return Array(7).join(char); // it shows 6( if aaaa shows aaaaaa)
// else ???
return sequence;
});
}
Using lodash:
_.uniq('aaabbbccc').join(''); // gives 'abc'
Per the actual question: "if the letter doesn't repeat its not shown"
function unique_char(str)
{
var obj = new Object();
for (var i = 0; i < str.length; i++)
{
var chr = str[i];
if (chr in obj)
{
obj[chr] += 1;
}
else
{
obj[chr] = 1;
}
}
var multiples = [];
for (key in obj)
{
// Remove this test if you just want unique chars
// But still keep the multiples.push(key)
if (obj[key] > 1)
{
multiples.push(key);
}
}
return multiples.join("");
}
var str = "aaabbbccc";
document.write(unique_char(str));
Your problem is that you are adding to unique every time you find the character in string. Really you should probably do something like this (since you specified the answer must be a nested for loop):
function unique_char(string){
var str_length=string.length;
var unique='';
for(var i=0; i<str_length; i++){
var foundIt = false;
for(var j=0; j<unique.length; j++){
if(string[i]==unique[j]){
foundIt = true;
break;
}
}
if(!foundIt){
unique+=string[i];
}
}
return unique;
}
document.write( unique_char('aaabbbccc'))
In this we only add the character found in string to unique if it isn't already there. This is really not an efficient way to do this at all ... but based on your requirements it should work.
I can't run this since I don't have anything handy to run JavaScript in ... but the theory in this method should work.
Try this if duplicate characters have to be displayed once, i.e.,
for i/p: aaabbbccc o/p: abc
var str="aaabbbccc";
Array.prototype.map.call(str,
(obj,i)=>{
if(str.indexOf(obj,i+1)==-1 ){
return obj;
}
}
).join("");
//output: "abc"
And try this if only unique characters(String Bombarding Algo) have to be displayed, add another "and" condition to remove the characters which came more than once and display only unique characters, i.e.,
for i/p: aabbbkaha o/p: kh
var str="aabbbkaha";
Array.prototype.map.call(str,
(obj,i)=>{
if(str.indexOf(obj,i+1)==-1 && str.lastIndexOf(obj,i-1)==-1){ // another and condition
return obj;
}
}
).join("");
//output: "kh"
<script>
uniqueString = "";
alert("Displays the number of a specific character in user entered string and then finds the number of unique characters:");
function countChar(testString, lookFor) {
var charCounter = 0;
document.write("Looking at this string:<br>");
for (pos = 0; pos < testString.length; pos++) {
if (testString.charAt(pos) == lookFor) {
charCounter += 1;
document.write("<B>" + lookFor + "</B>");
} else
document.write(testString.charAt(pos));
}
document.write("<br><br>");
return charCounter;
}
function findNumberOfUniqueChar(testString) {
var numChar = 0,
uniqueChar = 0;
for (pos = 0; pos < testString.length; pos++) {
var newLookFor = "";
for (pos2 = 0; pos2 <= pos; pos2++) {
if (testString.charAt(pos) == testString.charAt(pos2)) {
numChar += 1;
}
}
if (numChar == 1) {
uniqueChar += 1;
uniqueString = uniqueString + " " + testString.charAt(pos)
}
numChar = 0;
}
return uniqueChar;
}
var testString = prompt("Give me a string of characters to check", "");
var lookFor = "startvalue";
while (lookFor.length > 1) {
if (lookFor != "startvalue")
alert("Please select only one character");
lookFor = prompt(testString + "\n\nWhat should character should I look for?", "");
}
document.write("I found " + countChar(testString, lookFor) + " of the<b> " + lookFor + "</B> character");
document.write("<br><br>I counted the following " + findNumberOfUniqueChar(testString) + " unique character(s):");
document.write("<br>" + uniqueString)
</script>
Here is the simplest function to do that
function remove(text)
{
var unique= "";
for(var i = 0; i < text.length; i++)
{
if(unique.indexOf(text.charAt(i)) < 0)
{
unique += text.charAt(i);
}
}
return unique;
}
The one line solution will be to use Set. const chars = [...new Set(s.split(''))];
If you want to return values in an array, you can use this function below.
const getUniqueChar = (str) => Array.from(str)
.filter((item, index, arr) => arr.slice(index + 1).indexOf(item) === -1);
console.log(getUniqueChar("aaabbbccc"));
Alternatively, you can use the Set constructor.
const getUniqueChar = (str) => new Set(str);
console.log(getUniqueChar("aaabbbccc"));
Here is the simplest function to do that pt. 2
const showUniqChars = (text) => {
let uniqChars = "";
for (const char of text) {
if (!uniqChars.includes(char))
uniqChars += char;
}
return uniqChars;
};
const countUnique = (s1, s2) => new Set(s1 + s2).size
a shorter way based on #le_m answer
let unique=myArray.filter((item,index,array)=>array.indexOf(item)===index)
I have to make a function in JavaScript that removes all duplicated letters in a string. So far I've been able to do this: If I have the word "anaconda" it shows me as a result "anaconda" when it should show "cod". Here is my code:
function find_unique_characters( string ){
var unique='';
for(var i=0; i<string.length; i++){
if(unique.indexOf(string[i])==-1){
unique += string[i];
}
}
return unique;
}
console.log(find_unique_characters('baraban'));
We can also now clean things up using filter method:
function removeDuplicateCharacters(string) {
return string
.split('')
.filter(function(item, pos, self) {
return self.indexOf(item) == pos;
})
.join('');
}
console.log(removeDuplicateCharacters('baraban'));
Working example:
function find_unique_characters(str) {
var unique = '';
for (var i = 0; i < str.length; i++) {
if (str.lastIndexOf(str[i]) == str.indexOf(str[i])) {
unique += str[i];
}
}
return unique;
}
console.log(find_unique_characters('baraban'));
console.log(find_unique_characters('anaconda'));
If you only want to return characters that appear occur once in a string, check if their last occurrence is at the same position as their first occurrence.
Your code was returning all characters in the string at least once, instead of only returning characters that occur no more than once. but obviously you know that already, otherwise there wouldn't be a question ;-)
Just wanted to add my solution for fun:
function removeDoubles(string) {
var mapping = {};
var newString = '';
for (var i = 0; i < string.length; i++) {
if (!(string[i] in mapping)) {
newString += string[i];
mapping[string[i]] = true;
}
}
return newString;
}
With lodash:
_.uniq('baraban').join(''); // returns 'barn'
You can put character as parameter which want to remove as unique like this
function find_unique_characters(str, char){
return [...new Set(str.split(char))].join(char);
}
function find_unique_characters(str, char){
return [...new Set(str.split(char))].join(char);
}
let result = find_unique_characters("aaaha ok yet?", "a");
console.log(result);
//One simple way to remove redundecy of Char in String
var char = "aaavsvvssff"; //Input string
var rst=char.charAt(0);
for(var i=1;i<char.length;i++){
var isExist = rst.search(char.charAt(i));
isExist >=0 ?0:(rst += char.charAt(i) );
}
console.log(JSON.stringify(rst)); //output string : avsf
For strings (in one line)
removeDuplicatesStr = str => [...new Set(str)].join('');
For arrays (in one line)
removeDuplicatesArr = arr => [...new Set(arr)]
Using Set:
removeDuplicates = str => [...new Set(str)].join('');
Thanks to David comment below.
DEMO
function find_unique_characters( string ){
unique=[];
while(string.length>0){
var char = string.charAt(0);
var re = new RegExp(char,"g");
if (string.match(re).length===1) unique.push(char);
string=string.replace(re,"");
}
return unique.join("");
}
console.log(find_unique_characters('baraban')); // rn
console.log(find_unique_characters('anaconda')); //cod
var str = 'anaconda'.split('');
var rmDup = str.filter(function(val, i, str){
return str.lastIndexOf(val) === str.indexOf(val);
});
console.log(rmDup); //prints ["c", "o", "d"]
Please verify here: https://jsfiddle.net/jmgy8eg9/1/
Using Set() and destructuring twice is shorter:
const str = 'aaaaaaaabbbbbbbbbbbbbcdeeeeefggggg';
const unique = [...new Set([...str])].join('');
console.log(unique);
Yet another way to remove all letters that appear more than once:
function find_unique_characters( string ) {
var mapping = {};
for(var i = 0; i < string.length; i++) {
var letter = string[i].toString();
mapping[letter] = mapping[letter] + 1 || 1;
}
var unique = '';
for (var letter in mapping) {
if (mapping[letter] === 1)
unique += letter;
}
return unique;
}
Live test case.
Explanation: you loop once over all the characters in the string, mapping each character to the amount of times it occurred in the string. Then you iterate over the items (letters that appeared in the string) and pick only those which appeared only once.
function removeDup(str) {
var arOut = [];
for (var i=0; i < str.length; i++) {
var c = str.charAt(i);
if (c === '_') continue;
if (str.indexOf(c, i+1) === -1) {
arOut.push(c);
}
else {
var rx = new RegExp(c, "g");
str = str.replace(rx, '_');
}
}
return arOut.join('');
}
I have FF/Chrome, on which this works:
var h={};
"anaconda".split("").
map(function(c){h[c] |= 0; h[c]++; return c}).
filter(function(c){return h[c] == 1}).
join("")
Which you can reuse if you write a function like:
function nonRepeaters(s) {
var h={};
return s.split("").
map(function(c){h[c] |= 0; h[c]++; return c}).
filter(function(c){return h[c] == 1}).
join("");
}
For older browsers that lack map, filter etc, I'm guessing that it could be emulated by jQuery or prototype...
This code worked for me on removing duplicate(repeated) characters from a string (even if its words separated by space)
Link: Working Sample JSFiddle
/* This assumes you have trim the string and checked if it empty */
function RemoveDuplicateChars(str) {
var curr_index = 0;
var curr_char;
var strSplit;
var found_first;
while (curr_char != '') {
curr_char = str.charAt(curr_index);
/* Ignore spaces */
if (curr_char == ' ') {
curr_index++;
continue;
}
strSplit = str.split('');
found_first = false;
for (var i=0;i<strSplit.length;i++) {
if(str.charAt(i) == curr_char && !found_first)
found_first = true;
else if (str.charAt(i) == curr_char && found_first) {
/* Remove it from the string */
str = setCharAt(str,i,'');
}
}
curr_index++;
}
return str;
}
function setCharAt(str,index,chr) {
if(index > str.length-1) return str;
return str.substr(0,index) + chr + str.substr(index+1);
}
Here's what I used - haven't tested it for spaces or special characters, but should work fine for pure strings:
function uniquereduce(instring){
outstring = ''
instringarray = instring.split('')
used = {}
for (var i = 0; i < instringarray.length; i++) {
if(!used[instringarray[i]]){
used[instringarray[i]] = true
outstring += instringarray[i]
}
}
return outstring
}
Just came across a similar issue (finding the duplicates). Essentially, use a hash to keep track of the character occurrence counts, and build a new string with the "one-hit wonders":
function oneHitWonders(input) {
var a = input.split('');
var l = a.length;
var i = 0;
var h = {};
var r = "";
while (i < l) {
h[a[i]] = (h[a[i]] || 0) + 1;
i += 1;
}
for (var c in h) {
if (h[c] === 1) {
r += c;
}
}
return r;
}
Usage:
var a = "anaconda";
var b = oneHitWonders(a); // b === "cod"
Try this code, it works :)
var str="anaconda";
Array.prototype.map.call(str,
(obj,i)=>{
if(str.indexOf(obj,i+1)==-1 && str.lastIndexOf(obj,i-1)==-1){
return obj;
}
}
).join("");
//output: "cod"
This should work using Regex ;
NOTE: Actually, i dont know how this regex works ,but i knew its 'shorthand' ,
so,i would have Explain to you better about meaning of this /(.+)(?=.*?\1)/g;.
this regex only return to me the duplicated character in an array ,so i looped through it to got the length of the repeated characters .but this does not work for a special characters like "#" "_" "-", but its give you expected result ; including those special characters if any
function removeDuplicates(str){
var REPEATED_CHARS_REGEX = /(.+)(?=.*?\1)/g;
var res = str.match(REPEATED_CHARS_REGEX);
var word = res.slice(0,1);
var raw = res.slice(1);
var together = new String (word+raw);
var fer = together.toString();
var length = fer.length;
// my sorted duplicate;
var result = '';
for(var i = 0; i < str.length; i++) {
if(result.indexOf(str[i]) < 0) {
result += str[i];
}
}
return {uniques: result,duplicates: length};
} removeDuplicates('anaconda')
The regular expression /([a-zA-Z])\1+$/ is looking for:
([a-zA-Z]]) - A letter which it captures in the first group; then
\1+ - immediately following it one or more copies of that letter; then
$ - the end of the string.
Changing it to /([a-zA-Z]).*?\1/ instead searches for:
([a-zA-Z]) - A letter which it captures in the first group; then
.*? - zero or more characters (the ? denotes as few as possible); until
\1 - it finds a repeat of the first matched character.
I have 3 loopless, one-line approaches to this.
Approach 1 - removes duplicates, and preserves original character order:
var str = "anaconda";
var newstr = str.replace(new RegExp("[^"+str.split("").sort().join("").replace(/(.)\1+/g, "").replace(/[.?*+^$[\]\\(){}|-]/g, "\\$&")+"]","g"),"");
//cod
Approach 2 - removes duplicates but does NOT preserve character order, but may be faster than Approach 1 because it uses less Regular Expressions:
var str = "anaconda";
var newstr = str.split("").sort().join("").replace(/(.)\1+/g, "");
//cdo
Approach 3 - removes duplicates, but keeps the unique values (also does not preserve character order):
var str = "anaconda";
var newstr = str.split("").sort().join("").replace(/(.)(?=.*\1)/g, "");
//acdno
function removeduplicate(str) {
let map = new Map();
// n
for (let i = 0; i < str.length; i++) {
if (map.has(str[i])) {
map.set(str[i], map.get(str[i]) + 1);
} else {
map.set(str[i], 1);
}
}
let res = '';
for (let i = 0; i < str.length; i++) {
if (map.get(str[i]) === 1) {
res += str[i];
}
}
// o (2n) - > O(n)
// space o(n)
return res;
}
If you want your function to just return you a unique set of characters in your argument, this piece of code might come in handy.
Here, you can also check for non-unique values which are being recorded in 'nonUnique' titled array:
function remDups(str){
if(!str.length)
return '';
var obj = {};
var unique = [];
var notUnique = [];
for(var i = 0; i < str.length; i++){
obj[str[i]] = (obj[str[i]] || 0) + 1;
}
Object.keys(obj).filter(function(el,ind){
if(obj[el] === 1){
unique+=el;
}
else if(obj[el] > 1){
notUnique+=el;
}
});
return unique;
}
console.log(remDups('anaconda')); //prints 'cod'
If you want to return the set of characters with their just one-time occurrences in the passed string, following piece of code might come in handy:
function remDups(str){
if(!str.length)
return '';
var s = str.split('');
var obj = {};
for(var i = 0; i < s.length; i++){
obj[s[i]] = (obj[s[i]] || 0) + 1;
}
return Object.keys(obj).join('');
}
console.log(remDups('anaconda')); //prints 'ancod'
function removeDuplicates(str) {
var result = "";
var freq = {};
for(i=0;i<str.length;i++){
let char = str[i];
if(freq[char]) {
freq[char]++;
} else {
freq[char] =1
result +=char;
}
}
return result;
}
console.log(("anaconda").split('').sort().join('').replace(/(.)\1+/g, ""));
By this, you can do it in one line.
output: 'cdo'
function removeDuplicates(string){
return string.split('').filter((item, pos, self)=> self.indexOf(item) == pos).join('');
}
the filter will remove all characters has seen before using the index of item and position of the current element
Method 1 : one Simple way with just includes JS- function
var data = 'sssssddddddddddfffffff';
var ary = [];
var item = '';
for (const index in data) {
if (!ary.includes(data[index])) {
ary[index] = data[index];
item += data[index];
}
}
console.log(item);
Method 2 : Yes we can make this possible without using JavaScript function :
var name = 'sssssddddddddddfffffff';
let i = 0;
let newarry = [];
for (let singlestr of name) {
newarry[i] = singlestr;
i++;
}
// now we have new Array and length of string
length = i;
function getLocation(recArray, item, arrayLength) {
firstLaction = -1;
for (let i = 0; i < arrayLength; i++) {
if (recArray[i] === item) {
firstLaction = i;
break;
}
}
return firstLaction;
}
let finalString = '';
for (let b = 0; b < length; b++) {
const result = getLocation(newarry, newarry[b], length);
if (result === b) {
finalString += newarry[b];
}
}
console.log(finalString); // sdf
// Try this way
const str = 'anaconda';
const printUniqueChar = str => {
const strArr = str.split("");
const uniqueArray = strArr.filter(el => {
return strArr.indexOf(el) === strArr.lastIndexOf(el);
});
return uniqueArray.join("");
};
console.log(printUniqueChar(str)); // output-> cod
function RemDuplchar(str)
{
var index={},uniq='',i=0;
while(i<str.length)
{
if (!index[str[i]])
{
index[str[i]]=true;
uniq=uniq+str[i];
}
i++;
}
return uniq;
}
We can remove the duplicate or similar elements in string using for loop and extracting string methods like slice, substring, substr
Example if you want to remove duplicate elements such as aababbafabbb:
var data = document.getElementById("id").value
for(var i = 0; i < data.length; i++)
{
for(var j = i + 1; j < data.length; j++)
{
if(data.charAt(i)==data.charAt(j))
{
data = data.substring(0, j) + data.substring(j + 1);
j = j - 1;
console.log(data);
}
}
}
Please let me know if you want some additional information.