Efficiency and potential problems
You could use a Map but as you are counting word occurrences using an object is a little more efficient.
Efficiency
Your code can be improved as it is highly inefficient with each word needing to create a new object and fill its properties from the previous one, then add or update then next word. You need only create one object and add properties to it as you find them.
function mapMagazine (text) {
return text.split(' ')
.reduce((map, word) => (
map[word] = map[word] ? map[word] + 1 : 1, map
), {});
}
or using forEach
,
function mapMagazine (text) {
const map = {};
text.split(' ').forEach(w => map[w] = map[w] ? map[w] + 1 : 1);
return map;
}
or the (slightly) more performant version using a for
loop
function mapMagazine (text) {
const map = {};
for (const w of text.split(' ')) { map[w] = map[w] ? map[w] + 1 : 1 }
return map;
}
Problems
I do however see that your code would suffer from problems with a sting such as "A is a, as an a at the beginning, a capitalised A."
(Note it has a double space in it) It would return with some of the following properties...
{
A : 1,
"a," : 1,
a : 2,
"A." : 1,
"beginning," : 1,
"" : 1, // empty string from splitting two spaces
.. and the rest
}
I would imagine you would want something a little more like.
{
a : 5,
beginning : 1,
.. and the rest
}
To do this you need a slight mod to the function. The text should be converted to lowercase, split can use a RegExp to split into words on white spaces or groups of white spaces, and a check for empty string that can result if the text is ended on a white space such as a full stop.
BTW does the function really map magazines?
function mapWords(text) {
const map = {};
for (const word of text.toLowerCase().split(/\W+/)) {
word !== "" && (map[word] = map[word] ? map[word] + 1 : 1);
}
return map;
}