Related
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 am new to js.
can you tell me how to print like this * "a" -> "a1" * "aabbbaa" -> "a2b3a2"
i tried with hash map but test cases failing.
providing my code below.
i am not good in hash map.
can you tell me how to solve with hash map so that in future I can fix it my self.
not sure what data structure to use for this one.
providing my code below.
const _ = require("underscore");
const rle = ( input ) => {
console.log("input--->" + input);
//var someString ="aaa";
var someString = input;
var arr = someString.split("");
var numberCount = {};
for(var i=0; i< arr.length; i++) {
var alphabet = arr[i];
if(numberCount[alphabet]){
numberCount[alphabet] = numberCount[alphabet] + 1;
}
else{
numberCount[alphabet] = 1;
}
}
console.log("a:" + numberCount['a'], "b:" + numberCount['b']);
}
/**
* boolean doTestsPass()
* Returns true if all the tests pass. Otherwise returns false.
*/
/**
* Returns true if all tests pass; otherwise, returns false.
*/
const doTestsPass = () => {
const VALID_COMBOS = {"aaa": "a3", "aaabbc":"a3b2c1"};
let testPassed = true;
_.forEach(VALID_COMBOS, function(value, key) {
console.log(key, rle(key));
if (value !== rle(key)) {
testPassed = false;
}
});
return testPassed;
}
/**
* Main execution entry.
*/
if(doTestsPass())
{
console.log("All tests pass!");
}
else
{
console.log("There are test failures.");
}
You could
match groups of characters,
get the character and the count and
join it to a string.
function runLengthEncoding(string) {
return string
.match(/(.)\1*/g) // keep same characters in a single string
.map(s => s[0] + s.length) // take first character of string and length
.join(''); // create string of array
}
console.log(['a', 'aaa', 'aaabbc'].map(runLengthEncoding));
This is a bit more understandable version which iterates the given string and count the characters. If a different character is found, the last character and count is added to the result string.
At the end, a check is made, to prevent counting of empty strings and the last character cound is added to the result.
function runLengthEncoding(string) {
var result = '',
i,
count = 0,
character = string[0];
for (i = 0; i < string.length; i++) {
if (character === string[i]) {
count++;
continue;
}
result += character + count;
character = string[i];
count = 1;
}
if (count) {
result += character + count;
}
return result;
}
console.log(['', 'a', 'aaa', 'aaabbc'].map(runLengthEncoding));
You can reduce the array into a multidimensional array. map and join the array to convert to string.
const rle = (input) => {
return input.split("").reduce((c, v) => {
if (c[c.length - 1] && c[c.length - 1][0] === v) c[c.length - 1][1]++;
else c.push([v, 1]);
return c;
}, []).map(o => o.join('')).join('');
}
console.log(rle("a"));
console.log(rle("aabbbaa"));
console.log(rle("aaaaaa"));
Your function rle doesn't return a result.
Also note, this implementation may pass the test cases you wrote, but not the examples you mentioned in your question: for the string "aabbaa" this will produce "a4b2", not " a2b2a2" .
A simpler solution:
function runLengthEncoding(str) {
let out = "";
for (let i = 0; i < str.length; ++i) {
let temp = str[i];
let count = 1;
while (i < str.length && str[i+1] == temp) {
++count;
++i;
}
out += temp + count;
} // end-for
return out;
}
console.log(runLengthEncoding("a"));
console.log(runLengthEncoding("aabbbaa"));
console.log(runLengthEncoding("aaaaaa"));
I was messing around with the first question here: Reduce duplicate characters to a desired minimum and am looking for more elegant answers than what I came up with. It passes the test but curious to see other solutions. The sample tests are:
reduceString('aaaabbbb', 2) 'aabb'
reduceString('xaaabbbb', 2) 'xaabb'
reduceString('aaaabbbb', 1) 'ab'
reduceString('aaxxxaabbbb', 2) 'aaxxaabb'
and my solution (that passes these tests):
reduceString = function(str, amount) {
var count = 0;
var result = '';
for (var i = 0; i < str.length; i++) {
if (str[i] === str[i+1]) {
count++;
if (count < amount) {
result += str[i];
}
} else {
count = 0;
result += str[i];
}
};
return result;
}
Just use regular expressions.
var reduceString = function (str, amount) {
var re = new RegExp("(.)(?=\\1{" + amount + "})","g");
return str.replace(re, "");
}
I guess my best solution would be like
var str = "axxxaabbbbcaaxxxaab",
redStr = (s,n) => s.replace(/(\w)\1+/g,"$1".repeat(n));
console.log(redStr(str,2));
I tried to make it as short as possible:
reduceString = function(str, amount) {
var finalString = '', cL = '', counter;
str.split('').forEach(function(i){
if (i !== cL) counter = 0;
counter++;
cL = i;
if (counter <= amount ) finalString = finalString + i;
});
return finalString;
}
You can use reg expression instead. tested in javascript.
how it works:
(.) //match any character
\1 //if it follow by the same character
+{2 //more than 1 times
/g //global
$1 //is 1 time by $1$1 is 2 times
reduceString('aaaabbbb', 2)
reduceString('xaaabbbb', 2)
reduceString('aaaabbbb', 1)
reduceString('aaxxxaabbbb', 2)
function reduceString(txt,num)
{
var canRepeat=['$1'];
for (i=1;i<num;i++)
{
canRepeat.push('$1')
}
canRepeat = canRepeat.join('');
console.log(txt.replace(/(.)\1{2,}/g, canRepeat))
}
With regex:
var reduceString = function(str, amount) {
var x = [ ...new Set(str) ];
for (var c of x){
var rex = new RegExp(c + '{'+amount+',}','g');
str = str.replace(rex,string(c,amount));
}
return str;
};
var string = function(c,amount){
for(var i=0,s="";i<amount;i++)s+=c;
return s;
};
Up above regex solutions are much more better, but here is my accepted solution with reduce:
make an array from string via spread operator
Check the previous item
find how many times char is repeated in result string
otherwise concat result string with the current char
Don`t forget to use the second argument as the initial value, and return for each cases
reduceString = function(str, amount) {
return [...str].reduce(((res, cur)=>{
if(res.length && cur === res[res.length-1]){
dupsCount = [...res].filter(char => char === cur).length
if(dupsCount===amount){
return res;
}
else {
res+=cur;
return res;
}
}
res+=cur;
return res;
}),"")
}
I have a csv string like this "1,2,3" and want to be able to remove a desired value from it.
For example if I want to remove the value: 2, the output string should be the following:
"1,3"
I'm using the following code but seems to be ineffective.
var values = selectedvalues.split(",");
if (values.length > 0) {
for (var i = 0; i < values.length; i++) {
if (values[i] == value) {
index = i;
break;
}
}
if (index != -1) {
selectedvalues = selectedvalues.substring(0, index + 1) + selectedvalues.substring(index + 3);
}
}
else {
selectedvalues = "";
}
var removeValue = function(list, value, separator) {
separator = separator || ",";
var values = list.split(separator);
for(var i = 0 ; i < values.length ; i++) {
if(values[i] == value) {
values.splice(i, 1);
return values.join(separator);
}
}
return list;
}
If the value you're looking for is found, it's removed, and a new comma delimited list returned. If it is not found, the old list is returned.
Thanks to Grant Wagner for pointing out my code mistake and enhancement!
John Resign (jQuery, Mozilla) has a neat article about JavaScript Array Remove which you might find useful.
function removeValue(list, value) {
return list.replace(new RegExp(",?" + value + ",?"), function(match) {
var first_comma = match.charAt(0) === ',',
second_comma;
if (first_comma &&
(second_comma = match.charAt(match.length - 1) === ',')) {
return ',';
}
return '';
});
};
alert(removeValue('1,2,3', '1')); // 2,3
alert(removeValue('1,2,3', '2')); // 1,3
alert(removeValue('1,2,3', '3')); // 1,2
values is now an array. So instead of doing the traversing yourself.
Do:
var index = values.indexOf(value);
if(index >= 0) {
values.splice(index, 1);
}
removing a single object from a given index.
hope this helps
Here are 2 possible solutions:
function removeValue(list, value) {
return list.replace(new RegExp(value + ',?'), '')
}
function removeValue(list, value) {
list = list.split(',');
list.splice(list.indexOf(value), 1);
return list.join(',');
}
removeValue('1,2,3', '2'); // "1,3"
Note that this will only remove first occurrence of a value.
Also note that Array.prototype.indexOf is not part of ECMAScript ed. 3 (it was introduced in JavaScript 1.6 - implemented in all modern implementations except JScript one - and is now codified in ES5).
// Note that if the source is not a proper CSV string, the function will return a blank string ("").
function removeCsvVal(var source, var toRemove) //source is a string of comma-seperated values,
{ //toRemove is the CSV to remove all instances of
var sourceArr = source.split(","); //Split the CSV's by commas
var toReturn = ""; //Declare the new string we're going to create
for (var i = 0; i < sourceArr.length; i++) //Check all of the elements in the array
{
if (sourceArr[i] != toRemove) //If the item is not equal
toReturn += sourceArr[i] + ","; //add it to the return string
}
return toReturn.substr(0, toReturn.length - 1); //remove trailing comma
}
To apply it too your var values:
var values = removeVsvVal(selectedvalues, "2");
guess im too slow but here is what i would do
<script language="javascript">
function Remove(value,replaceValue)
{ var result = ","+value+",";
result = result.replace(","+replaceValue+",",",");
result = result.substr(1,result.length);
result = result.substr(0,result.length-1);
alert(result);
}
Remove("1,2,3",2)
</script>
adding , before and after the string ensure that u only remove the exact string u want
function process(csv,valueToDelete) {
var tmp = ","+csv;
tmp = tmp.replace(","+valueToDelete,"");
if (tmp.substr(0,1) == ',') tmp = tmp.substr(1);
return tmp;
}
use splice, pop or shift. depending on your requirement.
You could also have "find" the indexes of items in your array that match by using a function like the one found here : http://www.hunlock.com/blogs/Ten_Javascript_Tools_Everyone_Should_Have
var tmp = [5,9,12,18,56,1,10,42,'blue',30, 7,97,53,33,30,35,27,30,'35','Ball', 'bubble'];
// 0/1/2 /3 /4/5 /6 /7 /8 /9/10/11/12/13/14/15/16/17/ 18/ 19/ 20
var thirty=tmp.find(30); // Returns 9, 14, 17
var thirtyfive=tmp.find('35'); // Returns 18
var thirtyfive=tmp.find(35); // Returns 15
var haveBlue=tmp.find('blue'); // Returns 8
var notFound=tmp.find('not there!'); // Returns false
var regexp1=tmp.find(/^b/); // returns 8,20 (first letter starts with b)
var regexp1=tmp.find(/^b/i); // returns 8,19,20 (same as above but ignore case)
Array.prototype.find = function(searchStr) {
var returnArray = false;
for (i=0; i<this.length; i++) {
if (typeof(searchStr) == 'function') {
if (searchStr.test(this[i])) {
if (!returnArray) { returnArray = [] }
returnArray.push(i);
}
} else {
if (this[i]===searchStr) {
if (!returnArray) { returnArray = [] }
returnArray.push(i);
}
}
}
return returnArray;
}
or
var csv_remove_val = function(s, val, sep) {
var sep = sep || ",", a = s.split(sep), val = ""+val, pos;
while ((pos = a.indexOf(val)) >= 0) a.splice(pos, 1);
return a.join(sep);
}
What's the best and most efficient way to count keywords in JavaScript? Basically, I'd like to take a string and get the top N words or phrases that occur in the string, mainly for the use of suggesting tags. I'm looking more for conceptual hints or links to real-life examples than actual code, but I certainly wouldn't mind if you'd like to share code as well. If there are particular functions that would help, I'd also appreciate that.
Right now I think I'm at using the split() function to separate the string by spaces and then cleaning punctuation out with a regular expression. I'd also want it to be case-insensitive.
Cut, paste + execute demo:
var text = "Text to be examined to determine which n words are used the most";
// Find 'em!
var wordRegExp = /\w+(?:'\w{1,2})?/g;
var words = {};
var matches;
while ((matches = wordRegExp.exec(text)) != null)
{
var word = matches[0].toLowerCase();
if (typeof words[word] == "undefined")
{
words[word] = 1;
}
else
{
words[word]++;
}
}
// Sort 'em!
var wordList = [];
for (var word in words)
{
if (words.hasOwnProperty(word))
{
wordList.push([word, words[word]]);
}
}
wordList.sort(function(a, b) { return b[1] - a[1]; });
// Come back any time, straaanger!
var n = 10;
var message = ["The top " + n + " words are:"];
for (var i = 0; i < n; i++)
{
message.push(wordList[i][0] + " - " + wordList[i][1] + " occurance" +
(wordList[i][1] == 1 ? "" : "s"));
}
alert(message.join("\n"));
Reusable function:
function getTopNWords(text, n)
{
var wordRegExp = /\w+(?:'\w{1,2})?/g;
var words = {};
var matches;
while ((matches = wordRegExp.exec(text)) != null)
{
var word = matches[0].toLowerCase();
if (typeof words[word] == "undefined")
{
words[word] = 1;
}
else
{
words[word]++;
}
}
var wordList = [];
for (var word in words)
{
if (words.hasOwnProperty(word))
{
wordList.push([word, words[word]]);
}
}
wordList.sort(function(a, b) { return b[1] - a[1]; });
var topWords = [];
for (var i = 0; i < n; i++)
{
topWords.push(wordList[i][0]);
}
return topWords;
}
Once you have that array of words cleaned up, and let's say you call it wordArray:
var keywordRegistry = {};
for(var i = 0; i < wordArray.length; i++) {
if(keywordRegistry.hasOwnProperty(wordArray[i]) == false) {
keywordRegistry[wordArray[i]] = 0;
}
keywordRegistry[wordArray[i]] = keywordRegistry[wordArray[i]] + 1;
}
// now keywordRegistry will have, as properties, all of the
// words in your word array with their respective counts
// this will alert (choose something better than alert) all words and their counts
for(var keyword in keywordRegistry) {
alert("The keyword '" + keyword + "' occurred " + keywordRegistry[keyword] + " times");
}
That should give you the basics of doing this part of the work.
Try to split you string on words and count the resulting words, then sort on the counts.
This builds upon a previous answer by insin by only having one loop:
function top_words(text, n) {
// Split text on non word characters
var words = text.toLowerCase().split(/\W+/)
var positions = new Array()
var word_counts = new Array()
for (var i=0; i<words.length; i++) {
var word = words[i]
if (!word) {
continue
}
if (typeof positions[word] == 'undefined') {
positions[word] = word_counts.length
word_counts.push([word, 1])
} else {
word_counts[positions[word]][1]++
}
}
// Put most frequent words at the beginning.
word_counts.sort(function (a, b) {return b[1] - a[1]})
// Return the first n items
return word_counts.slice(0, n)
}
// Let's see if it works.
var text = "Words in here are repeated. Are repeated, repeated!"
alert(top_words(text, 3))
The result of the example is: [['repeated',3], ['are',2], ['words', 1]]
I would do exactly what you have mentioned above to isolate each word. I would then probably add each word as the index of an array with the number of occurrences as the value.
For example:
var a = new Array;
a[word] = a[word]?a[word]+1:1;
Now you know how many unique words there are (a.length) and how many occurrences of each word existed (a[word]).