forked from exercism/python
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
…exercism#891) * parallel-letter-frequency: Implement exercise to resolve exercism#744 * parallel-letter-frequency: Removed infinite loop * parallel-letter-frequency: README format fixes
- Loading branch information
Showing
5 changed files
with
157 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
2 changes: 2 additions & 0 deletions
2
exercises/parallel-letter-frequency/parallel_letter_frequency.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
def calculate(text_input): | ||
pass |
61 changes: 61 additions & 0 deletions
61
exercises/parallel-letter-frequency/parallel_letter_frequency_test.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | ||
|
||
|
||
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() |