1

I am trying to rework this function, so it returns more than one value. As of now, it only returns the first one, so if I have a sentence with the words "Hello to all from Boston", it will only return Hello, I am looking to reword this function so, it returns ["Hello", "all", "Boston"].

By the way, I got this solution from this previous thread.

function returnFirstRepeatChar2(str){
   return ((str = str.split(' ').map(function(word){
     var letters = word.split('').reduce(function(map, letter){
       map[letter] = map.hasOwnProperty(letter) ? map[letter] + 1 : 1;
       return map;
     }, {}); // map of letter to number of occurrence in the word.
     
     return {
       word: word,
       count: Object.keys(letters).filter(function(letter){
         return letters[letter] > 1;
       }).length // number of repeated letters
     };
   }).sort(function(a, b){
     return b.count - a.count;
   }).shift()) && str.count && str.word) || -1; //return first word with maximum repeated letters or -1
}
console.log(returnFirstRepeatChar2("Hello and hello again"));

And here is a bin. By the way this is just one of the solutions of the original thread, not sure if its the best performing one.

Community
  • 1
  • 1
Lucky500
  • 677
  • 5
  • 17
  • 31
  • What is really your goal? Did not really understand the question. – rrk Feb 11 '16 at 16:59
  • @RejithRKrishnan OP wants to print all words from a string that have repeated letters (hello has 2 l, all has 2 l, boston has 2 o) – juvian Feb 11 '16 at 17:00
  • I apologize, perhaps my question was not well formulated. I want to return an array of words that have more than one character... .so if given the string "Hello all from Boston", I would get the result ["Hello", "all", "Boston"]... but if I have a word in that string with more of the same characters, say "Whooooa, Hello all from Boston", I want my array to return the word with the most repeated letters like so ["whooooa"] – Lucky500 Feb 12 '16 at 02:55

6 Answers6

1

Remove the .shift() at the end - filter out the words that don't have a repeated letter, then map the results to return just the words:

function returnFirstRepeatChar2(str){
    return str.split(' ').map(function(word) {
        var letters = word.split('').reduce(function(map, letter) {
           map[letter] = map.hasOwnProperty(letter) ? map[letter] + 1 : 1;
           return map;
         }, {}); // map of letter to number of occurrence in the word.

         return {
             word: word,
             count: Object.keys(letters).filter(function(letter) {
                 return letters[letter] > 1;
             }).length // number of repeated letters
         };
   }).sort(function(a, b) {
       return b.count - a.count;
   }).filter(function(obj) { //Remove words with no dup letters
       return obj.count;
   }).map(function(obj) { //Format the returned result
       return obj.word;
   });
}
console.log(returnFirstRepeatChar2("Hello and hello again")); //["Hello", "hello", "again"] is the result
tymeJV
  • 103,943
  • 14
  • 161
  • 157
  • Thanks for your example timeJV... but quick question, if I introduce another word with say 4 of the same characters, like "ssss", that should be be the only word in the array, since there is no other word with four of the same character, as of now, the function is showing any word with 2 or more of the same character.... – Lucky500 Feb 12 '16 at 02:48
1

You can use RegEx.

str.split(/\s+/) // Split the string by one or more spaces
    .filter(str => /(.).*?\1/.test(str)); // Filter the words containing repeating character

RegEx Explanation:

  1. (.): Match any single character and adds in the first capturing group
  2. .*?: Match any number of characters lazily until the condition satisfies
  3. \1: Backreference. Get the string that is matched in #1 i.e. first captured group

var str = "Hello to all from Boston";
var arr = str.split(/\s+/).filter(str => /(.).*?\1/.test(str));

console.log(arr);
document.getElementById('result').innerHTML = JSON.stringify(arr, 0, 4);
<pre id="result"></pre>

Live Demo:

var regex = /(.).*?\1/;
document.getElementById('textbox').addEventListener('keyup', function() {
  var arr = (this.value || '').split(/\s+/).filter(str => /(.).*?\1/.test(str)) || [];

  document.getElementById('result').innerHTML = JSON.stringify(arr, 0, 4);
}, false);
<input type="text" id="textbox" />
<pre id="result"></pre>
Tushar
  • 85,780
  • 21
  • 159
  • 179
0

Using the power of array functions , here is how I would solve it:

var str = "Hello to all from Boston"

var arr = str.split(" ").filter(function(word) { // for each word in the string
  var cache = {}; // we will check if it has repeated letters
  return word.split("").some(function(letter) { // for each letter in word
    if (cache.hasOwnProperty(letter)) { // if letter was already seen
      return true // return true, the word indeed has repeated letters, stop checking other letters
    };
    cache[letter] = 1; // if not, its the first time we see this letter, mark it
    return false; // and continue with next letter
  }) // if it had repeated letters, we return true, if not we discard it
})

console.log(arr) // ["Hello", "all", "Boston"]

More info on functions used:

Array.some()

Array.filter()

juvian
  • 15,875
  • 2
  • 37
  • 38
0

You seem to want a quick function... so avoid multiple splits, maps, reduce... etc... You have to parse your string only one time.

var parse = (str) => {
    "use strict";
    let i, s, 
        map = {
            word: ""
        }, 
        words = [];
    for (i = 0; s = str[i]; i++) {
        if (s === " ") {
            // end of the previous word
            // if the property "match" is true, the word is a match
            map["match"] && words.push(map["word"]);
            // set map back to an empty object for the next word
            map = {
                word: ""
               };
        } else {
            // map[s] already exists, we have a match
            if (map[s]) {
                map[s] += 1;
                map["match"] = true;
            // otherwise set to 1 map[s], we have an occurence of s
            } else {
                map[s] = 1;
            }
            // create the word in match["word"]
            map["word"] += s;           
        }
    }
    // dont forget the last word
    map["match"] && words.push(map["word"]);
    return words;
}

Please this is a quick snippet, not fully tested, but it would give you another approach...

0

Something a little simpler. Uses the dupe finder code from this answer.

function returnFirstRepeatChar2(str) {
  return str.split(' ').reduce(function (p, c) {
    var hasDupes = c.toLowerCase().split('').sort().join('').match(/(.)\1+/g);
    if (hasDupes) p.push(c);
    return p;
  }, []);  
}

returnFirstRepeatChar2('Hello to all from Boston'); // [ "Hello", "all", "Boston" ]

DEMO

Community
  • 1
  • 1
Andy
  • 61,948
  • 13
  • 68
  • 95
0

Wont this be enough???

function returnFirstRepeatChar2(str){
   strA = str.split(' ');
   repeats = [];
   for(i = 0; i < strA.length; i++)
     if( arr = strA[i].match(/([a-zA-Z]).*?\1/) )
       repeats.push(strA[i]);
  return repeats;
}
<input value="" onchange="alert(returnFirstRepeatChar2(this.value))">
rrk
  • 15,677
  • 4
  • 29
  • 45