I am new to coding and have been given this question to answer.
This question is;
Create a function that receives a string that will contain a number of mentions and hashtags as on Twitter.
E.g. "So excited to start @coding on Monday! #learntocode #codingbootcamp"
The function should return an object describing the number of hashtags and mentions found:
{ hashtags: 2, mentions: 1 }
The code that I have created is this;
function countHashtagsAndMentions(str) {
let split = str.split(" ");
let count = 0
for (let i = 9; i < str.length; i++) {
let hash = split.filter(hashtag => hashtag.match(/#/g))
if (hash === 1) {
count ++
}
let total = {
hash = count,
}
return hash
}
}
My code is being run against this;
describe("countHashtagsAndMentions", () => {
it("returns an object", () => {
expect(typeof countHashtagsAndMentions("")).to.equal("object");
});
it("returns {hashtags: 0, mentions: 0} if it finds none", () => {
expect(
countHashtagsAndMentions(
"hello this is a tweet guaranteed to get very little engagement"
)
).to.eql({ hashtags: 0, mentions: 0 });
});
it("recognises no mentions", () => {
expect(countHashtagsAndMentions("#yolo")).to.eql({
hashtags: 1,
mentions: 0
});
});
it("recognises no hashtags", () => {
expect(countHashtagsAndMentions("@yobo")).to.eql({
hashtags: 0,
mentions: 1
});
});
it("finds multiple hashtags and mentions and returns that number", () => {
expect(countHashtagsAndMentions("#yolo @bolo #golo")).to.eql({
hashtags: 2,
mentions: 1
});
expect(countHashtagsAndMentions("@boyo #goyo @loyo #zoyo")).to.eql({
hashtags: 2,
mentions: 2
});
expect(
countHashtagsAndMentions(
'"So excited to start at @northcoders on Monday! #learntocode #codingbootcamp"'
)
).to.eql({ hashtags: 2, mentions: 1 });
});
});
Dose anyone have any suggestion of haw to make my code work?
A simple loop does it. Since you're using ES2015+ syntax, a for-of
would work nicely:
function countHashtagsAndMentions(str) {
let hashtags = 0;
let mentions = 0;
for (const ch of str) {
if (ch === "#") {
++hashtags;
} else if (ch === "@") {
++mentions;
}
}
return {hashtags, mentions};
}
let str = "So excited to start @coding on Monday! #learntocode #codingbootcamp";
console.log(countHashtagsAndMentions(str));
That works because strings are iterable in ES2015+. The for-of
loop implicitly uses the iterator from the string to walk through its characters. So within the loop, ch
is each character from the string. Note that unlike str.split()
, a strings iterator doens't separately the two halves of a character that requires a surrogate pair (like most emojis), which is normally what you want.
This:
for (const ch of str) {
// ...
}
is effectively the same as
let it = str[Symbol.iterator]();
let rec;
while (!(rec = it.next()).done) {
const ch = rec.value;
// ...
}
but without the it
and rec
variables.
Alternately, you could use replace
with a regular expression to replace all characters other than the ones you want to count. It sounds like it would be more expensive, but it's something the JavaScript engine can optimize:
function countHashtagsAndMentions(str) {
return {
hashtags: str.replace(/[^#]/g, "").length,
mentions: str.replace(/[^@]/g, "").length
};
}
let str = "So excited to start @coding on Monday! #learntocode #codingbootcamp";
console.log(countHashtagsAndMentions(str));
Which you use probably depends in part on the length of the string. The replace
option is nice and short, but does go through the string twice.