0

I'm trying to check what letters repeat in a string by creating a new array of only the repeated letters using the .filter() method but I only want the letter to appear one time, no matter how many times it repeats.

This is what I tried:

const fullName = "Muhammad Ali";
const fullNameLowercase = fullName.toLowerCase();
const splitName = fullNameLowercase.split("");

let repeats = splitName.filter((letter, index) => {return splitName.indexOf(letter) !== index});
console.log(repeats); // prints [ 'm', 'm', 'a', 'a' ]

I want it to only add the letter once to the array repeats, how do I do it? Is there any other more efficient way to do what I want that doesn't use .filter()?

3
  • what do you expect from repeats var? Commented Nov 17, 2022 at 18:39
  • @ElMehdi in this example I'm trying to get ['m', 'a'] instead of [ 'm', 'm', 'a', 'a' ] Commented Nov 17, 2022 at 18:41
  • 1
    [...new Set(['a', 'a'])] => ['a'] Commented Nov 17, 2022 at 18:48

7 Answers 7

1

Simply by wrapping up repeats variable with Set constructor and the spread syntax: to avoid duplicates values:

const fullName = "Muhammad Ali";
const fullNameLowercase = fullName.toLowerCase();
const splitName = fullNameLowercase.split("");

let repeats = splitName.filter((letter, index) => splitName.indexOf(letter) !== index);
const repeatsNoDuplicates = [... new Set(repeats)];
console.log(repeatsNoDuplicates); // prints [ 'm', 'a']

Tip: use implicit return by remove the curly braces and return keyword from an arrow function it is implied that you return the expression code tells it to do.

Sign up to request clarification or add additional context in comments.

Comments

1

Is there any other more efficient way to do what I want that doesn't use .filter()?

Sure, an efficient solution would be to use a counting hash table, run your string through it and collect keys those counts are > 1:

let str = "Muhammad Ali"
let counter = new Map

for (let char of str.toLowerCase())
  counter.set(char, 1 + (counter.get(char) ?? 0))

let repeats = []

for (let [char, count] of counter)
  if (count > 1)
    repeats.push(char)
    
console.log(repeats)

Comments

0

You can combine it with the reduce method like so :

const fullName = 'Muhammad Ali';
const fullNameLowercase = fullName.toLowerCase();
const splitName = fullNameLowercase.split('');

let repeats = splitName
  .filter((e, i) => splitName.indexOf(e) !== i)
  /* we create an empty array and for every letter :
    - if the letter is already in the array: don't do anything
    - if the letter isn't already in the array: add it to the array
    it returns us the array without duplicates
  */
  .reduce((g, c) => g.includes(c) ? g : g.concat([c]), []);
  
console.log(repeats);

1 Comment

The existing answer using a Set is much simpler
0

Add another Array.filter() to the end of the line:

filter((ltr, idx, arr) => arr.indexOf(ltr)  != idx);

const fullName = "Muhammad Ali";
const fullNameLowercase = fullName.toLowerCase();
const splitName = fullNameLowercase.split("");

let repeats = splitName.filter((letter, index) => {
  return splitName.indexOf(letter) !== index;
}).filter((ltr, idx, arr) => arr.indexOf(ltr)  != idx);

console.log(repeats);

Comments

0

maybe you can do that... ?

const repeatLetters=s=>Object.keys([...s.toLowerCase()].reduce((r,c,i,a)=>((a.indexOf(c)<i)?r[c]='':'',r),{}))  

console.log( repeatLetters('Muhammad Ali') )

1 Comment

it would be more helpful to post non-minified code
0
  • filter() and .test() filters out any non-letter characters.
  • .reduce() returns an object that has the count of occurrences of each letter.
  • Object.entries() converts the object returned by .reduce() to an array of key/values.
  • .flatMap() filters out any letter occurring once.

Example B is just a slightly smaller version of Example A

Example A

const string =  `"Float like a butterfly, sting like a bee."
                                             - Muhammad Ali`;

const repeats = text => {
  let letters = text.toLowerCase().split("").filter(a => /[a-z]/.test(a));
  let counts = letters.reduce((prv, cur) => {
    if (!prv[cur]) {
      prv[cur] = 1;
    } else {
      prv[cur]++;
    }
    return prv;
  }, {});
  console.log("Letter quantities: ")
  console.log(counts)
  return Object.entries(counts).flatMap(([key, val]) => val > 1 ? key : []);
}

console.log("Repeated letters: "+repeats(string));

Example B

const string = `"Float like a butterfly, sting like a bee."
                                             - Muhammad Ali`;

const repeats = text => {
  return Object.entries(text.toLowerCase().split("").filter(a => /[a-z]/.test(a)).reduce((prv, cur) => {
    if (!prv[cur]) prv[cur] = 1;
    else prv[cur]++;
    return prv;
  }, {})).flatMap(([key, val]) => val > 1 ? key : []);
}

console.log("Repeated letters: " + repeats(string));

Comments

0

You can use [...new Set(repeats)] as in the demo below:

const fullName = "Muhammad Ali";
const fullNameLowercase = fullName.toLowerCase();
const splitName = fullNameLowercase.split("");

let repeats = [...new Set(splitName.filter((letter, index) => {return splitName.indexOf(letter) !== index}))];

console.log(repeats); // prints [ 'm', 'a' ]

Alternatively ....

You can start by obtaining all unique letters in the string and then using Array#filter to return those that repeat:

const 
    fullName = "Muhammad Ali",
    fullNameLowercase = fullName.toLowerCase(),
    uniques = [...new Set(fullNameLowercase.split(""))],

    output = uniques.filter(l => fullNameLowercase.split(l).length > 2);
    //OR output = uniques.filter(l => fullNameLowercase.match(new RegExp(`[${l}]`,'g')).length > 1);

console.log( output ); //[ 'm', 'a' ]

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.