Given a phrase, count the occurrences of each word in that phrase.
For example for the input "olly olly in come free"
olly: 2
in: 1
come: 1
free: 1
To run the tests, run the command busted
from within the exercise directory.
For more detailed information about the Lua track, including how to get help if you're having trouble, please visit the exercism.io Lua language page.
This is a classic toy problem, but we were reminded of it by seeing it in the Go Tour.
It's possible to submit an incomplete solution so you can see how others have completed the exercise.
local word_count = require('word-count').word_count
describe('word-count', function()
it('counts one word', function()
local result = word_count('word')
local expected = { word = 1 }
assert.are.same(expected, result)
end)
it('counts one of each', function()
local result = word_count('one of each')
local expected = { one = 1, of = 1, each = 1 }
assert.are.same(expected, result)
end)
it('counts multiple occurrences', function()
local result = word_count('one fish two fish red fish blue fish')
local expected = { one = 1, fish = 4, two = 1, red = 1, blue = 1 }
assert.are.same(expected, result)
end)
it('ignores punctuation', function()
local result = word_count('car : carpet as java : javascript!!&@$%^&')
local expected = { car = 1, carpet = 1, as = 1, java = 1, javascript = 1 }
assert.are.same(expected, result)
end)
it('includes numbers', function()
local result = word_count('testing, 1, 2 testing')
local expected = { testing = 2, ['1'] = 1, ['2'] = 1 }
assert.are.same(expected, result)
end)
it('normalizes case', function()
local result = word_count('go Go GO')
local expected = { go = 3 }
assert.are.same(expected, result)
end)
end)
local function update_result(word_table, word_normalized_table, new_word)
if type(word_table[new_word]) ~= 'nil' then -- if original word exists either in the table or normalized metatable
if type(word_table[new_word]) == 'number' then -- increase count if the word already exists
word_table[new_word] = word_table[new_word] + 1
else -- if it does not exist then look into metatable and get the key (word) and increase that word count
word_table[word_normalized_table[new_word:lower()]] = word_table[word_normalized_table[new_word:lower()]] + 1
end
elseif type(word_table[new_word:lower()]) ~= 'nil' then -- normalized word exists either in the table or normalized metatable
word_table[word_normalized_table[new_word:lower()]] = word_table[word_normalized_table[new_word:lower()]] + 1
else -- register word in both original and normalized metatable if it is the first time
word_table[new_word] = 1
word_normalized_table[new_word:lower()] = new_word
end
end
return {
word_count = function (source)
local word_table = {}
local word_normalized_table = {}
setmetatable(word_table, {__index = word_normalized_table})
for new_word in source:gmatch("%w+") do
update_result(word_table, word_normalized_table, new_word)
end
return word_table
end
}
A huge amount can be learned from reading other people’s code. This is why we wanted to give exercism users the option of making their solutions public.
Here are some questions to help you reflect on this solution and learn the most from it.
Level up your programming skills with 3,449 exercises across 52 languages, and insightful discussion with our volunteer team of welcoming mentors. Exercism is 100% free forever.
Sign up Learn More
Community comments
I may misunderstood the last test in spec file. 'normalizes case' I thought it supposed to treat all mixed lower and upper case letters as same and it should be the first word in the test string. so in my solution it will give different answer for the following case. 'go Go GO' -> go = 3 'Go go GO' -> Go = 3 (since the Go is the first 'go' in the test array) Now I figured out by looking at others' solution.. that 'normalizes case' means all lower case.. so 'Go GO GO' should be go = 3 (at least.. I figured out how to use metatable and method.. though :-))
Neat solution! But you're right, you only need to make everything lower case :)