Remove characters from a string which occurs more than twice

Viewed 608

I want to remove the third occurrence of a character from a string.

Below is what I tried from my end:

function unique(list) {
    var result = [];
    function findOccurrences(arr, val) {
        var i, j,
            count = 0;
        for (i = 0, j = arr.length; i < j; i++) {
            (arr[i] === val) && count++;
        }
        return count;
    }
    $.each(list, function(i, e) {
        if (findOccurrences(list, e) < 3) result.push(e);
    });
    return result.join("");
}
var srting = "DGHKHHNL";
var thelist = srting.split("")
console.log(unique(thelist));

Here are some expected results:

Input: DGHKHHNL

Expected: DGHKHNL

Input: AFKLABAYBIB

Expected: AFKLABYBI

Input: JNNNKNND

Expected: JNNKD

https://regex101.com/r/WmUPWW/1 .. I tried using this regex as well to solve the issue. But this this doesn't solves the issue as well.

Please help

4 Answers

Instead of counting the occurrences, you should check the occurrence count for the specific index you are evaluating. Basically, if it's the 3rd or more time that it has appeared, then you don't want it.

A slight change to your code can achieve this (you may want to choose a better function name):

function unique(list) {
  var result = [];

  function findOccurrenceIndex(arr, val, index) {
    var i, j,
      count = 0;
    for (i = 0, j = arr.length; i < j; i++) {
      (arr[i] === val) && count++;
      if (i == index) {
        return count;
      }
    }
    return count;
  }

  $.each(list, function(i, e) {
    if (findOccurrenceIndex(list, e, i) < 3) result.push(e);
  });

  return result.join("");
}
var srting = "DGHKHHNL";
var thelist = srting.split("")
console.log(unique(thelist));

Here is a working example


Note that this answer is based on your current code, I expect you could refactor the logic to reduce the code clutter.

In fact, the following reduces the code to a single loop. It works by building a dictionary of character counts as it works though the list. (It also doesn't rely on JQuery like your original attempt):

function unique(list) {
  var result = [];
  var counts = {};

  for (var i = 0; i < list.length; i++) {
    var c = list[i];
    if (!counts[c])
      counts[c] = 0;
    counts[c]++;
    if (counts[c] < 3) {
      result.push(c);
    }
  }

  return result.join("");
}

Here is a working example

An alternate approach which doesn't rely on jQuery (although you could easily swap that with a forEach):

function unique(str) {
    var count = {}
    return str.split("").reduce((acc, cur) => {
        if (!(cur in count)) {
            count[cur] = 1;
            acc.push(cur);
            return acc;
        }

        if (count[cur] == 2) return acc;

        acc.push(cur);
        count[cur]++;
        return acc;
    }, []).join("");
}

Here I used two helper array result and tempCount . tempCount is store each alphabet as key and count it ,so if it is exceed more than 3

function unique(list) {
    var result = [];
    var tempCount = [];
    list = list.split("");
    for(var i=0;i < list.length;i++) {
        if(tempCount[list[i]]) {
            if(tempCount[list[i]] == 2) continue;
            tempCount[list[i]]++;
        } else {
            tempCount[list[i]] = 1;            
        }
        result.push(list[i]);
    }
    return result.join("");
}
var srting = "JNNNKNND";
console.log(unique(srting));

Building off the answer by @musefan, another ES6 approach can use Array.reduce to build the counts/output based on an accumulator object:

const onlyTwo = list => list.split('').reduce((cache, letter) => {
  cache[letter] ? cache[letter]++ : cache[letter] = 1;
  if (cache[letter] < 3) cache.output += letter;
  return cache;
}, {
  output: ''
}).output;

console.log(onlyTwo('DGHKHHNL'));
console.log(onlyTwo('AFKLABAYBIB'));
console.log(onlyTwo('JNNNKNND'));

You can improve this by applying functional programming principles to separate the concerns of counting the duplicates and generating the output string. This way you can utilize the same accumulation technique with different max values.

const maxDuplicates = max => list => list.split('').reduce((cache, letter) => {
  cache[letter] ? cache[letter]++ : cache[letter] = 1;
  if (cache[letter] <= max) cache.output += letter;
  return cache;
}, {
  output: ''
}).output;

const onlyTwo = maxDuplicates(2);

console.log(onlyTwo('DGHKHHNL'));
console.log(onlyTwo('AFKLABAYBIB'));
console.log(onlyTwo('JNNNKNND'));

const onlyOne = maxDuplicates(1);

console.log(onlyOne('DGHKHHNL'));
console.log(onlyOne('AFKLABAYBIB'));
console.log(onlyOne('JNNNKNND'));

Related