What are some clean ways to print out last characters of all words in a string. For example, a phrase like "laugh ride lol hall bozo " --> "hello" and "dog polo boo sudd noob smiley ride " --> goodbye.
These lines would return "1" and undefined. Any help is much appreciated.
var decrypt = function (message) {
var solution = [];
for (var i = 0; i < message.length; i++) {
if(message.charAt(i)===" ") {
return solution.push(message.charAt(i-1));
};
};
};
var resulta = decrypt("laugh ride lol hall bozo ")
console.log(resulta); // logs "hello"
var resultb = decrypt("dog polo boo sudd noob smiley ride ")
console.log(resultb); // logs "goodbye"
Don't return inside the loop, just append the charater to the result. When the loop is done, return what you want. Since you apparently want to return a string, you don't need an array.
var decrypt = function (message) {
var solution = '';
for (var i = 0; i < message.length; i++) {
if(message.charAt(i)===" ") {
solution += message.charAt(i-1);
};
};
return solution;
};
var resulta = decrypt("laugh ride lol hall bozo ")
console.log(resulta); // logs "hello"
var resultb = decrypt("dog polo boo sudd noob smiley ride ")
console.log(resultb); // logs "goodbye"
Assuming the words are separated by spaces you can do it in one line:
var decrypt = function (message) {
return (message+" ").match(/\w\s/g).join("").replace(/\s/g,"");
}
The regex /\w\s/g will match a word character followed by a space. The .match() method will return an array of all such matches. .join() will join the array elements into a string. And then .replace() will remove the spaces from that string.
Note that I'm using (message+" ") to add an extra space to the input string just in case it doesn't already have one at the end.
Also the code I showed doesn't allow for strings that don't have any "word characters" in them. If you want to test for that you need two lines:
var decrypt = function (message) {
var m = (message+" ").match(/\w\s/g);
return m ? m.join("").replace(/\s/g,"") : "";
//include default value for non match here^^
}
Another clean solution is
var decrypt = function (message) {
return message.split(' ')
.map(function(word) { return word.slice(-1); })
.join('');
}
This is relies on Array.prototype.map, which was added in ES5 with support for all modern browsers (http://kangax.github.io/compat-table/es5/#Array.prototype.map).
Considering you only care about the last character of each word, I would loop through the string in reverse. This allows you to also print the last character in the string without appending a space on the end of the encoded message.
function decrypt(message) {
var c, secret = '', lastSpace = true;
for (var i = (message || '').length - 1; i >= 0; i--, lastSpace = c === ' ') {
c = message.charAt(i);
if (lastSpace) secret = c + secret;
}
return secret;
}
Related
May I ask my first question. Sorry if the title is so bad. It was a bit annoy me. So I was build a function to reverse a string that have 5 character or more like this.
function spinWords(str) {
str2 = str.split(" ");
str3 = [];
for (i = 0; i < str2.length; i++) {
str3 = str2[i].split("");
if (str3.length >= 5) {
str3.reverse();
}
str4 = str3.join("");
return str4;
}
}
spinWords("Welcome To The Club");`
The output that I expected is like this
emocleW To The Club
But that code output is this
emocleW
To
The
Club
Is there any solution, at least to combine the four iteration string into one line?
Every help would be very nice. Thanks!!!
function spinWords(str) {
function reverseString(str) {
return str.split("").reverse().join("");
}
const words = str.split(" ");
const spinnedWords = words.map(word => {
if (word.length >=5 ) return reverseString(word);
else return word;
});
return spinnedWords.join(' ');
}
spinWords("Welcome To The Club");
Seems you are printing the array which would give that result, you would need to join the array to get it on one line like so
myArray.join(" ");
A short example that would do the thing you want
function spinWords(str) {
return str.split(" ")
.map((word) => word.length > 4
? word.split('').reverse().join('') // Reverses a string
: word
)
.join(" ");
}
I am attempting this question on Codewars. I am not sure if am doing it right. Here is the question:
You are given a secret message you need to decipher. Here are the things you need to know to decipher it:
For each word:
the second and the last letter is switched (e.g. Hello becomes Holle)
the first letter is replaced by its character code (e.g. H becomes 72)
Note: there are no special characters used, only letters and spaces:
decipherThis('72olle 103doo 100ya'); // 'Hello good day'
decipherThis('82yade 115te 103o'); // 'Ready set go'
Now I have written this piece of code:
function decipherThis(str)
{
var msg = [];
msg.push(str.charCodeAt(0));
for (var i = 0; i<str.length; i++)
{
if (str[1] == true && str[1] != str[str.length])
{
msg.push(str[str.length]);
//str[1] = str[str.length]);
var news = str;
for (var j = 0; j<news.length; j++)
{
news[1] = news[news.length];
const newNew = delete news[0][1];
msg.push(newNew);
}
}
}
return msg;
};
var google = "hello"
decipherThis(google)
I am getting an error and I think I have created it for a single word. It does not understand words after blank spaces. Please help me fix this.
This is the error traceback:
Response received but no data was written to STDOUT or STDERR.
Please change characterCodeAt to charCodeAt and it will work.
characterCodeAt is not a valid method of a String class
The error is not Javascript related. It might occur because the decipherThis() function is returning an array instead of a string.
You could loop the original string backwards until the second character and concatonate it to the charcode of the first character like this:
function decipherThis(str)
{
var cipher = '',
words = str.split(' ');
for(var w = 0; w < words.length; w++) {
cipher += ' '+words[w].charCodeAt(0);
for(var i = words[w].length-1; i > 0; i--) {
cipher += words[w][i];
}
}
return cipher.trim();
}
The question is from freecodecamp Link
Fill in the urlSlug function so it converts a string title and returns the hyphenated version for the URL. You can use any of the methods covered in this section, and don't use replace. Here are the requirements:
The input is a string with spaces and title-cased words
The output is a string with the spaces between words replaced by a
hyphen (-)
The output should be all lower-cased letters
The output should not have any spaces
// the global variable
var globalTitle = " Winter Is Coming";
function urlSlug(title) {
let toArr = title.split("");
let newArr = toArr.map(a=> {
if(a==" "){
a= "-";
}
return a.toLowerCase();
} );
if(newArr[0] == "-"){
newArr.splice(0,1);
}
let finalArr = newArr.join("");
return finalArr;
}
// Add your code above this line
var winterComing = urlSlug(globalTitle); // Should be "winter-is-coming"
console.log(urlSlug(globalTitle));
Right now I have not been able to solve how I could get rid of the extra hyphen from the output.
I'm not supposed to use replace.
You could do this easily using trim() and a simple regex:
var globalTitle = " Winter Is Coming Now ";
var slug = globalTitle.trim().replace(/[ ]+/g, '-').toLowerCase();
console.log(slug);
[ ]+ ensures that any number of spaces (1 or more) gets replaced with a minus sign once.
If for some reason you can't use replace, you could use Array.filter() like so:
var title = " Winter Is Coming Now ";
var slug = title.split(" ").filter(word => word.length > 0).join("-").toLowerCase();
console.log(slug);
I was working on it till now , Haven't looked at the answers.
But I solved it this way. Might be inefficient.
// the global variable
var globalTitle = "Winter Is Coming";
function urlSlug(title) {
let toArr = title.split("");
let newArr = toArr.map(a=> {
if(a==" "){
a= "-";
}
return a.toLowerCase();
} );
if(newArr[0] == "-"){
newArr.splice(0,1);
}
for(let i=0;i<newArr.length;i++){
if(newArr[i-1]=="-"&& newArr[i]=="-")
{
newArr.splice(i,1,"");
}
}
let finalArr = newArr.join("");
return finalArr;
}
var winterComing = urlSlug(globalTitle); // Should be "winter-is-coming"
console.log(urlSlug(globalTitle));
Another option would be to continue your thought of split() and then use reduce to reduce the elements of the array to a single output:
var globalTitle = " Winter Is Coming";
function urlSlug(title) {
let split = title.split(' ');
return split.reduce((accumulator, currentValue, index) => {
if (currentValue.length > 0) {
accumulator += currentValue.toLowerCase();
accumulator += (index < split.length - 1) ? '-' : '';
}
return accumulator;
});
}
console.log(urlSlug(globalTitle));
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.
How can I implement javascript function to calculate frequency of each word in a given sentence.
this is my code:
function search () {
var data = document.getElementById('txt').value;
var temp = data;
var words = new Array();
words = temp.split(" ");
var uniqueWords = new Array();
var count = new Array();
for (var i = 0; i < words.length; i++) {
//var count=0;
var f = 0;
for (j = 0; j < uniqueWords.length; j++) {
if (words[i] == uniqueWords[j]) {
count[j] = count[j] + 1;
//uniqueWords[j]=words[i];
f = 1;
}
}
if (f == 0) {
count[i] = 1;
uniqueWords[i] = words[i];
}
console.log("count of " + uniqueWords[i] + " - " + count[i]);
}
}
am unable to trace out the problem ..any help is greatly appriciated.
output in this format:
count of is - 1
count of the - 2..
input: this is anil is kum the anil
Here is a JavaScript function to get the frequency of each word in a sentence:
function wordFreq(string) {
var words = string.replace(/[.]/g, '').split(/\s/);
var freqMap = {};
words.forEach(function(w) {
if (!freqMap[w]) {
freqMap[w] = 0;
}
freqMap[w] += 1;
});
return freqMap;
}
It will return a hash of word to word count. So for example, if we run it like so:
console.log(wordFreq("I am the big the big bull."));
> Object {I: 1, am: 1, the: 2, big: 2, bull: 1}
You can iterate over the words with Object.keys(result).sort().forEach(result) {...}. So we could hook that up like so:
var freq = wordFreq("I am the big the big bull.");
Object.keys(freq).sort().forEach(function(word) {
console.log("count of " + word + " is " + freq[word]);
});
Which would output:
count of I is 1
count of am is 1
count of big is 2
count of bull is 1
count of the is 2
JSFiddle: http://jsfiddle.net/ah6wsbs6/
And here is wordFreq function in ES6:
function wordFreq(string) {
return string.replace(/[.]/g, '')
.split(/\s/)
.reduce((map, word) =>
Object.assign(map, {
[word]: (map[word])
? map[word] + 1
: 1,
}),
{}
);
}
JSFiddle: http://jsfiddle.net/r1Lo79us/
I feel you have over-complicated things by having multiple arrays, strings, and engaging in frequent (and hard to follow) context-switching between loops, and nested loops.
Below is the approach I would encourage you to consider taking. I've inlined comments to explain each step along the way. If any of this is unclear, please let me know in the comments and I'll revisit to improve clarity.
(function () {
/* Below is a regular expression that finds alphanumeric characters
Next is a string that could easily be replaced with a reference to a form control
Lastly, we have an array that will hold any words matching our pattern */
var pattern = /\w+/g,
string = "I I am am am yes yes.",
matchedWords = string.match( pattern );
/* The Array.prototype.reduce method assists us in producing a single value from an
array. In this case, we're going to use it to output an object with results. */
var counts = matchedWords.reduce(function ( stats, word ) {
/* `stats` is the object that we'll be building up over time.
`word` is each individual entry in the `matchedWords` array */
if ( stats.hasOwnProperty( word ) ) {
/* `stats` already has an entry for the current `word`.
As a result, let's increment the count for that `word`. */
stats[ word ] = stats[ word ] + 1;
} else {
/* `stats` does not yet have an entry for the current `word`.
As a result, let's add a new entry, and set count to 1. */
stats[ word ] = 1;
}
/* Because we are building up `stats` over numerous iterations,
we need to return it for the next pass to modify it. */
return stats;
}, {} );
/* Now that `counts` has our object, we can log it. */
console.log( counts );
}());
const sentence = 'Hi my friend how are you my friend';
const countWords = (sentence) => {
const convertToObject = sentence.split(" ").map( (i, k) => {
return {
element: {
word: i,
nr: sentence.split(" ").filter(j => j === i).length + ' occurrence',
}
}
});
return Array.from(new Set(convertToObject.map(JSON.stringify))).map(JSON.parse)
};
console.log(countWords(sentence));
Here is an updated version of your own code...
<!DOCTYPE html>
<html>
<head>
<title>string frequency</title>
<style type="text/css">
#text{
width:250px;
}
</style>
</head>
<body >
<textarea id="txt" cols="25" rows="3" placeholder="add your text here"> </textarea></br>
<button type="button" onclick="search()">search</button>
<script >
function search()
{
var data=document.getElementById('txt').value;
var temp=data;
var words=new Array();
words=temp.split(" ");
var unique = {};
for (var i = 0; i < words.length; i++) {
var word = words[i];
console.log(word);
if (word in unique)
{
console.log("word found");
var count = unique[word];
count ++;
unique[word]=count;
}
else
{
console.log("word NOT found");
unique[word]=1;
}
}
console.log(unique);
}
</script>
</body>
I think your loop was overly complicated. Also, trying to produce the final count while still doing your first pass over the array of words is bound to fail because you can't test for uniqueness until you have checked each word in the array.
Instead of all your counters, I've used a Javascript object to work as an associative array, so we can store each unique word, and the count of how many times it occurs.
Then, once we exit the loop, we can see the final result.
Also, this solution uses no regex ;)
I'll also add that it's very hard to count words just based on spaces. In this code, "one, two, one" will results in "one," and "one" as being different, unique words.
While both of the answers here are correct maybe are better but none of them address OP's question (what is wrong with the his code).
The problem with OP's code is here:
if(f==0){
count[i]=1;
uniqueWords[i]=words[i];
}
On every new word (unique word) the code adds it to uniqueWords at index at which the word was in words. Hence there are gaps in uniqueWords array. This is the reason for some undefined values.
Try printing uniqueWords. It should give something like:
["this", "is", "anil", 4: "kum", 5: "the"]
Note there no element for index 3.
Also the printing of final count should be after processing all the words in the words array.
Here's corrected version:
function search()
{
var data=document.getElementById('txt').value;
var temp=data;
var words=new Array();
words=temp.split(" ");
var uniqueWords=new Array();
var count=new Array();
for (var i = 0; i < words.length; i++) {
//var count=0;
var f=0;
for(j=0;j<uniqueWords.length;j++){
if(words[i]==uniqueWords[j]){
count[j]=count[j]+1;
//uniqueWords[j]=words[i];
f=1;
}
}
if(f==0){
count[i]=1;
uniqueWords[i]=words[i];
}
}
for ( i = 0; i < uniqueWords.length; i++) {
if (typeof uniqueWords[i] !== 'undefined')
console.log("count of "+uniqueWords[i]+" - "+count[i]);
}
}
I have just moved the printing of count out of the processing loop into a new loop and added a if not undefined check.
Fiddle: https://jsfiddle.net/cdLgaq3a/
I had a similar assignment. This is what I did:
Assignment : Clean the following text and find the most frequent word (hint, use replace and regular expressions).
const sentence = '%I $am#% a %tea#cher%, &and& I lo%#ve %te#a#ching%;. The#re $is no#th#ing; &as& mo#re rewarding as educa#ting &and& #emp%o#weri#ng peo#ple. ;I found tea#ching m%o#re interesting tha#n any ot#her %jo#bs. %Do#es thi%s mo#tiv#ate yo#u to be a tea#cher!? %Th#is 30#Days&OfJavaScript &is al#so $the $resu#lt of &love& of tea&ching'
console.log(`\n\n 03.Clean the following text and find the most frequent word (hint, use replace and regular expressions) \n\n ${sentence} \n\n`)
console.log(`Cleared sentence : ${sentence.replace(/[.,\/#!$%\^&\*;:{}=\-_`~()#]/g, "")}`)
console.log(mostFrequentWord(sentence))
function mostFrequentWord(sentence) {
sentence = sentence.replace(/[.,\/#!$%\^&\*;:{}=\-_`~()#]/g, "").trim().toLowerCase()
let sentenceArray = sentence.split(" ")
let word = null
let count = 0
for (i = 0; i < sentenceArray.length; i++) {
word = sentenceArray[i]
count = sentence.match(RegExp(sentenceArray[i], 'gi')).length
if (count > count) {
count = count
word = word
}
}
return `\n Count of most frequent word "${word}" is ${count}`
}
I'd go with Sampson's match-reduce method for slightly better efficiency. Here's a modified version of it that is more production-ready. It's not perfect, but it should cover the vast majority of scenarios (i.e., "good enough").
function calcWordFreq(s) {
// Normalize
s = s.toLowerCase();
// Strip quotes and brackets
s = s.replace(/["“”(\[{}\])]|\B['‘]([^'’]+)['’]/g, '$1');
// Strip dashes and ellipses
s = s.replace(/[‒–—―…]|--|\.\.\./g, ' ');
// Strip punctuation marks
s = s.replace(/[!?;:.,]\B/g, '');
return s.match(/\S+/g).reduce(function(oFreq, sWord) {
if (oFreq.hasOwnProperty(sWord)) ++oFreq[sWord];
else oFreq[sWord] = 1;
return oFreq;
}, {});
}
calcWordFreq('A ‘bad’, “BAD” wolf-man...a good ol\' spook -- I\'m frightened!') returns
{
"a": 2
"bad": 2
"frightened": 1
"good": 1
"i'm": 1
"ol'": 1
"spook": 1
"wolf-man": 1
}