Unique words counter using javascript - javascript

I want to make a function uniqueWordCount which can count all unique words in a string (words.txt). I should be able to get the answer after returning it, and I have done something like this now:
let fs = require('fs');
function run() {
let text = fs.readFileSync('./words.txt', 'utf8');
return uniqueWordCount(text);
}
function uniqueWordCount(str) {
let count = 0;
let set = new Set();
let words = str.split (' ');
for(let i = 1; 1 < words.length; i++){
set.add(str[i]);
count = set.size;
}
return uniqueWordCount;
}
module.exports.run = run;

split the string on spaces using split() and make it a set. Set will remove the duplicates. Return the size of the set using size()
function uniqueWordCount(str) {
let set = new Set(str.split(' '));
return set.size;
}
console.log(uniqueWordCount('as as de we re'))

An ES5 & ES6 compliant solution could be:
"aabc adsd adsd hasd"
.split(/\b(?:\s+)?/)
.reduce(function(ac,d,i){!~ac.indexOf(d) && ac.push(d);return ac;},[]).length //return 3

Here are 4 changes you have to make to get your uniqueWordCount function to work:
Start your for-loop at let i = 0, not let i = 1
1 < words.length will ALWAYS be true, creating an infinite loop. Replace 1 with i -> i < words.length
In your for-loop access words[i], not str[i] since words is your array of words, str is just your original string.
You're returning a variable uniqueWordCount which is a function, but you need to return count which is storing the size of your set.
Here is how your function should now look:
function uniqueWordCount(str) {
let count = 0;
let set = new Set();
let words = str.split (' ');
// 1. replace 'let i = 1;' with 'let i = 0;'
// 2. replace the second condition 1 < words.length with i < words.length
for(let i = 1; i < words.length; i++){
// 3. replace 'str[i]' with 'words[i]'
set.add(words[i]);
count = set.size;
}
// 4. change 'uniqueWordCount' to 'count'
return count;
}
Note: You can and probably should get rid of your count variable and just return set.size at the end of your function. Then you will be able to avoid updating count on every iteration of your for-loop as well. This change is not required but would make your function nicer. Here is how it would look:
function uniqueWordCount(str) {
let set = new Set();
let words = str.split (' ');
for(let i = 1; i < words.length; i++){
set.add(words[i]);
}
return set.size;
}
One final optimization would be similar to what #ellipsis mentioned - creating a Set immediately while splitting your str string. Like this:
function uniqueWordCount(str) {
// automatically populate your 'Set'
let set = new Set(str.split (' '));
// immediately return your set's size
return set.size;
}
Note: If you want to count unique words regardless of case, you can immediately do str.toLowerCase() in your uniqueWordCount function.

function uniqueWordCount(str) {
var i = [];
return str.split(' ')
.map( e => (i[e] === undefined) ? i[e] = 1 : 0)
.reduce((accumulator, currentValue) => accumulator + currentValue);
}
console.log(uniqueWordCount("ws ws ws we we wf h"));

Related

Why does my function return 'undefiend' along with the value assigned to the varibale when it is previously declared?

// reverse the word
function wordReverse (input) {
// create variable to store new value
let newString = "";
// split string into array of seperate letters
let splitString = input.split('');
// run through word backwards and add array values to newString
for (let i = splitString.length; i >= 0; i--) {
newString += splitString[i];
}
// cannot get this not to return 'undefined'
return newString;
}
const test = wordReverse("word");
console.log(test);
Trying to get the word 'word' reversed, but returns:
'undefineddrow'
Tried declaring it with a value, delcaring it outside the function, etc but can't make it work.
In your for loop i should start at splitString.length - 1
for (let i = splitString.length - 1; i >= 0; i--) {
newString += splitString[i];
}

How can i solve this exercixe with String.prototype?

How can i create this to console log like this?
String.prototype.sheldonize = function () {
return `knock ${this}`
}
'Penny'.sheldonize(3)
I have this code at the moment, but I dont know how to repeat knock more times
Use the repeat method to establish a number of 'knocks' in the line and to establish how many times the line should repeat
String.prototype.sheldonize = function (repeats) {
const line = `${'knock '.repeat(repeats)}${this}, `.repeat(repeats)
return `${line.substring(0,line.length-2)}.`;
}
console.log('Penny'.sheldonize(3));
Using For Loop and repeat method
String.prototype.sheldonize = function(count) {
let ans = "";
for (let i = 0; i < count; i++) {
ans += "knock ";
}
ans = `${ans}${this}, `.repeat(count)
ans = ans.substring(0, ans.length - 2) + "."
return ans;
}
console.log('Penny'.sheldonize(3))
console.log('Penny'.sheldonize(2))
Create an array and on each iteration up to n - 1 add the string to it, finally joining it up and returning the string from the function.
// If you're adding to a prototype it's always best
// to double check to see if the method already exists
// no matter (in this case) how unlikely
if (!('sheldonize' in String.prototype)) {
String.prototype.sheldonize = function (n) {
// Create the array
const out = [];
// Create the string
const knock = 'knock '.repeat(n);
// Loop until `n - 1` has been reached
// pushing the string into the array
// on each iteration
for (let i = 0; i < n; i++) {
out.push(`${knock}${this}`);
}
// Finally return the joined array
return out.join(', ');
}
}
console.log('Penny'.sheldonize(3));
console.log('Penny'.sheldonize(2));
console.log('John'.sheldonize(4));
Additional documentation
repeat

Can a JavaScript loop, upon the second iteration, iterate from the result of the prior iteration?

I just joined Stack Overflow and this is my first post so please do not hesitate to let me know if I am doing anything wrong.
I was presented with a challenge to create a function that accepts a string and calls another given function which swaps indices until the string is returned backwards.
I have gotten as far as below:
//given function
function swap(str, first, last){
str = str.split('');
let firstIndex = str[first];
str[first] = str[last];
str[last] = firstIndex;
str = str.join("").toString()
return str;
}
//my function
let word = "Hello"
function reverseSwap(str) {
let result = ""
for (let i = 0; i < str.length/2; i++) {
result += swap(str, i, str.length -1 - i);
}
return result;
}
console.log(reverseSwap(word))
This however returns "oellHHlleoHello", because each iteration swaps indices from the original string then concatenates. Is it possible, upon the second iteration, to have the loop iterate from the result of the prior iteration so the following occurs?:
result of first iteration: swap(word, 0, 4) which returns "oellH"
second iteration uses "oellH" instead of "Hello" to swap(1, 3) which returns "olleH"
Then, swap(2,2) which doesn't change anything.
It's not working because
Don't += add all new strings to your result. (This will append each swap string to your result.)
You have to manipulate always the "result" string. (You want to do a swap always on the updated version of the string. Not the original one)
Here is a simple solution:
function swap(str, first, last) {
str = str.split("");
let firstIndex = str[first];
str[first] = str[last];
str[last] = firstIndex;
str = str.join("").toString();
return str;
}
let word = "Hello";
function reverseSwap(str) {
for (let i = 0; i < str.length / 2; i++) {
str = swap(str, i, str.length - 1 - i);
}
return str;
}
console.log(reverseSwap(word));

How to get odd and even position characters from a string?

I'm trying to figure out how to remove every second character (starting from the first one) from a string in Javascript.
For example, the string "This is a test!" should become "hsi etTi sats!"
I also want to save every deleted character into another array.
I have tried using replace method and splice method, but wasn't able to get them to work properly. Mostly because replace only replaces the first character.
function encrypt(text, n) {
if (text === "NULL") return n;
if (n <= 0) return text;
var encArr = [];
var newString = text.split("");
var j = 0;
for (var i = 0; i < text.length; i += 2) {
encArr[j++] = text[i];
newString.splice(i, 1); // this line doesn't work properly
}
}
You could reduce the characters of the string and group them to separate arrays using the % operator. Use destructuring to get the 2D array returned to separate variables
let str = "This is a test!";
const [even, odd] = [...str].reduce((r,char,i) => (r[i%2].push(char), r), [[],[]])
console.log(odd.join(''))
console.log(even.join(''))
Using a for loop:
let str = "This is a test!",
odd = [],
even = [];
for (var i = 0; i < str.length; i++) {
i % 2 === 0
? even.push(str[i])
: odd.push(str[i])
}
console.log(odd.join(''))
console.log(even.join(''))
It would probably be easier to use a regular expression and .replace: capture two characters in separate capturing groups, add the first character to a string, and replace with the second character. Then, you'll have first half of the output you need in one string, and the second in another: just concatenate them together and return:
function encrypt(text) {
let removedText = '';
const replacedText1 = text.replace(/(.)(.)?/g, (_, firstChar, secondChar) => {
// in case the match was at the end of the string,
// and the string has an odd number of characters:
if (!secondChar) secondChar = '';
// remove the firstChar from the string, while adding it to removedText:
removedText += firstChar;
return secondChar;
});
return replacedText1 + removedText;
}
console.log(encrypt('This is a test!'));
Pretty simple with .reduce() to create the two arrays you seem to want.
function encrypt(text) {
return text.split("")
.reduce(({odd, even}, c, i) =>
i % 2 ? {odd: [...odd, c], even} : {odd, even: [...even, c]}
, {odd: [], even: []})
}
console.log(encrypt("This is a test!"));
They can be converted to strings by using .join("") if you desire.
I think you were on the right track. What you missed is replace is using either a string or RegExp.
The replace() method returns a new string with some or all matches of a pattern replaced by a replacement. The pattern can be a string or a RegExp, and the replacement can be a string or a function to be called for each match. If pattern is a string, only the first occurrence will be replaced.
Source: String.prototype.replace()
If you are replacing a value (and not a regular expression), only the first instance of the value will be replaced. To replace all occurrences of a specified value, use the global (g) modifier
Source: JavaScript String replace() Method
So my suggestion would be to continue still with replace and pass the right RegExp to the function, I guess you can figure out from this example - this removes every second occurrence for char 't':
let count = 0;
let testString = 'test test test test';
console.log('original', testString);
// global modifier in RegExp
let result = testString.replace(/t/g, function (match) {
count++;
return (count % 2 === 0) ? '' : match;
});
console.log('removed', result);
like this?
var text = "This is a test!"
var result = ""
var rest = ""
for(var i = 0; i < text.length; i++){
if( (i%2) != 0 ){
result += text[i]
} else{
rest += text[i]
}
}
console.log(result+rest)
Maybe with split, filter and join:
const remaining = myString.split('').filter((char, i) => i % 2 !== 0).join('');
const deleted = myString.split('').filter((char, i) => i % 2 === 0).join('');
You could take an array and splice and push each second item to the end of the array.
function encrypt(string) {
var array = [...string],
i = 0,
l = array.length >> 1;
while (i <= l) array.push(array.splice(i++, 1)[0]);
return array.join('');
}
console.log(encrypt("This is a test!"));
function encrypt(text) {
text = text.split("");
var removed = []
var encrypted = text.filter((letter, index) => {
if(index % 2 == 0){
removed.push(letter)
return false;
}
return true
}).join("")
return {
full: encrypted + removed.join(""),
encrypted: encrypted,
removed: removed
}
}
console.log(encrypt("This is a test!"))
Splice does not work, because if you remove an element from an array in for loop indexes most probably will be wrong when removing another element.
I don't know how much you care about performance, but using regex is not very efficient.
Simple test for quite a long string shows that using filter function is on average about 3 times faster, which can make quite a difference when performed on very long strings or on many, many shorts ones.
function test(func, n){
var text = "";
for(var i = 0; i < n; ++i){
text += "a";
}
var start = new Date().getTime();
func(text);
var end = new Date().getTime();
var time = (end-start) / 1000.0;
console.log(func.name, " took ", time, " seconds")
return time;
}
function encryptREGEX(text) {
let removedText = '';
const replacedText1 = text.replace(/(.)(.)?/g, (_, firstChar, secondChar) => {
// in case the match was at the end of the string,
// and the string has an odd number of characters:
if (!secondChar) secondChar = '';
// remove the firstChar from the string, while adding it to removedText:
removedText += firstChar;
return secondChar;
});
return replacedText1 + removedText;
}
function encrypt(text) {
text = text.split("");
var removed = "";
var encrypted = text.filter((letter, index) => {
if(index % 2 == 0){
removed += letter;
return false;
}
return true
}).join("")
return encrypted + removed
}
var timeREGEX = test(encryptREGEX, 10000000);
var timeFilter = test(encrypt, 10000000);
console.log("Using filter is faster ", timeREGEX/timeFilter, " times")
Using actually an array for storing removed letters and then joining them is much more efficient, than using a string and concatenating letters to it.
I changed an array to string in filter solution to make it the same like in regex solution, so they are more comparable.

Javascript Adding leading zeros works with while loop but not for loop

I'm extracting number from a string and passing it to a function. I want to add 1 to it and then return the string while retaining the leading zeros. I was able to do it using a while loop but not a for loop. The for loop simply skips the zeros.
var addMoreZeros = (numStr)=> {
let newNumStr = (parseInt(numStr)+1).toString();
let zerosToAdd = numStr.length - newNumStr.length;
let zeroPadStr = "";
let i = 0;
while (i < zerosToAdd) {
zeroPadStr += "0";
i++;
}
//This doesn't work
//for(let i = 0; i++; i < zerosToAdd) {
// zeroPadStr+="0";
//}
return zeroPadStr + newNumStr;
}
You have your for loop syntax wrong, it should be:
(initializer; condition; increments / decrements)
so:
for(let i = 0; i < zerosToAdd; i++) {}
var addMoreZeros = (numStr)=> {
let newNumStr = (parseInt(numStr)+1).toString();
let zerosToAdd = numStr.length - newNumStr.length;
let zeroPadStr = "";
for(let i = 0; i < zerosToAdd; i++) {
zeroPadStr+="0";
}
return zeroPadStr + newNumStr;
}
console.log(addMoreZeros("00125"))
Alternative approach (instead of using for/while):
var addMoreZeros = (numStr, numLength = numStr.length) => `${++numStr}`.padStart(numLength,'0');
// example of usage
console.log(addMoreZeros("124", 5));
Explanation ++numStr coerces the numeric string to a number and increments it, then `${...}` casts the number back to a string. Finally padStart() adds leading zeros.

Categories

Resources