Home > Enterprise >  Finding repeated elements in an array using .filter() - javascript
Finding repeated elements in an array using .filter() - javascript

Time:11-18

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()?

CodePudding user response:

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.

CodePudding user response:

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)

CodePudding user response:

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);

CodePudding user response:

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);

CodePudding user response:

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') )

CodePudding user response:

  • 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));

CodePudding user response:

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' ]

  • Related