-
-
Notifications
You must be signed in to change notification settings - Fork 1.4k
parallel-letter-frequency: Implement exercise to resolve #744 #891
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
a563108
21a60a6
9753b28
67276ba
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
# Parallel Letter Frequency | ||
|
||
Count the frequency of letters in texts using parallel computation. | ||
|
||
Parallelism is about doing things in parallel that can also be done | ||
sequentially. A common example is counting the frequency of letters. | ||
Create a function that returns the total frequency of each letter in a | ||
list of texts and that employs parallelism. | ||
|
||
The letters used consists of ASCII letters `a` to `z`, inclusive, and is case | ||
insensitive. | ||
|
||
## Submitting Exercises | ||
|
||
Note that, when trying to submit an exercise, make sure the solution is in the `exercism/python/<exerciseName>` directory. | ||
|
||
For example, if you're submitting `bob.py` for the Bob exercise, the submit command would be something like `exercism submit <path_to_exercism_dir>/python/bob/bob.py`. | ||
|
||
|
||
For more detailed information about running tests, code style and linting, | ||
please see the [help page](http://exercism.io/languages/python). | ||
|
||
## Submitting Incomplete Solutions | ||
It's possible to submit an incomplete solution so you can see how others have completed the exercise. |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
# -*- coding: utf-8 -*- | ||
from collections import Counter | ||
from threading import Lock, Thread | ||
from time import sleep | ||
import sys | ||
if sys.version[0] == '2': | ||
from Queue import Queue | ||
else: | ||
from queue import Queue | ||
|
||
total_workers = 3 # Maximum number of threads chosen arbitrarily | ||
|
||
|
||
class LetterCounter(object): | ||
|
||
def __init__(self): | ||
self.lock = Lock() | ||
self.value = Counter() | ||
|
||
def add_counter(self, counter_to_add): | ||
self.lock.acquire() | ||
try: | ||
self.value = self.value + counter_to_add | ||
finally: | ||
self.lock.release() | ||
|
||
|
||
def count_letters(queue_of_texts, letter_to_frequency, worker_id): | ||
while not queue_of_texts.empty(): | ||
sleep(worker_id + 1) | ||
line_input = queue_of_texts.get() | ||
if line_input is not None: | ||
letters_in_line = Counter([x for x in line_input.lower() if | ||
x.isalpha()]) | ||
letter_to_frequency.add_counter(letters_in_line) | ||
queue_of_texts.task_done() | ||
if line_input is None: | ||
break | ||
|
||
|
||
def calculate(list_of_texts): | ||
queue_of_texts = Queue() | ||
[queue_of_texts.put(line) for line in list_of_texts] | ||
letter_to_frequency = LetterCounter() | ||
threads = [] | ||
for i in range(total_workers): | ||
worker = Thread(target=count_letters, args=(queue_of_texts, | ||
letter_to_frequency, i)) | ||
worker.start() | ||
threads.append(worker) | ||
queue_of_texts.join() | ||
for i in range(total_workers): | ||
queue_of_texts.put(None) | ||
for t in threads: | ||
t.join() | ||
return letter_to_frequency.value |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
def calculate(text_input): | ||
pass |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
# -*- coding: utf-8 -*- | ||
from collections import Counter | ||
import unittest | ||
|
||
from parallel_letter_frequency import calculate | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Could you please also leave a comment stating what version of
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I was unable to find a canonical-data.json in https://github.com/exercism/problem-specifications/tree/master/exercises/parallel-letter-frequency. I noticed that there is an open task for creating one (exercism/problem-specifications#574). Should I still add the comment? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @forgeRW probably. You can point out that there was no |
||
|
||
class ParallelLetterFrequencyTest(unittest.TestCase): | ||
def test_one_letter(self): | ||
actual = calculate(['a']) | ||
expected = {'a': 1} | ||
self.assertDictEqual(actual, expected) | ||
|
||
def test_case_insensitivity(self): | ||
actual = calculate(['aA']) | ||
expected = {'a': 2} | ||
self.assertDictEqual(actual, expected) | ||
|
||
def test_numbers(self): | ||
actual = calculate(['012', '345', '6789']) | ||
expected = {} | ||
self.assertDictEqual(actual, expected) | ||
|
||
def test_punctuations(self): | ||
actual = calculate(['[]\;,', './{}|', ':"<>?']) | ||
expected = {} | ||
self.assertDictEqual(actual, expected) | ||
|
||
def test_whitespaces(self): | ||
actual = calculate([' ', '\t ', '\n\n']) | ||
expected = {} | ||
self.assertDictEqual(actual, expected) | ||
|
||
def test_repeated_string_with_known_frequencies(self): | ||
letter_frequency = 3 | ||
text_input = 'abc\n' * letter_frequency | ||
actual = calculate(text_input.split('\n')) | ||
expected = {'a': letter_frequency, 'b': letter_frequency, | ||
'c': letter_frequency} | ||
self.assertDictEqual(actual, expected) | ||
|
||
def test_multiline_text(self): | ||
text_input = "3 Quotes from Excerism Homepage:\n" + \ | ||
"\tOne moment you feel like you're\n" + \ | ||
"getting it. The next moment you're\n" + \ | ||
"stuck.\n" + \ | ||
"\tYou know what it’s like to be fluent.\n" + \ | ||
"Suddenly you’re feeling incompetent\n" + \ | ||
"and clumsy.\n" + \ | ||
"\tHaphazard, convoluted code is\n" + \ | ||
"infuriating, not to mention costly. That\n" + \ | ||
"slapdash explosion of complexity is an\n" + \ | ||
"expensive yak shave waiting to\n" + \ | ||
"happen." | ||
actual = calculate(text_input.split('\n')) | ||
expected = Counter([x for x in text_input.lower() if x.isalpha()]) | ||
self.assertDictEqual(actual, expected) | ||
|
||
|
||
if __name__ == '__main__': | ||
unittest.main() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just an alternative:
There is a convention to use
_
if the variable isn't really requiredFor
threads