Skip to content

Commit d795d0b

Browse files
Add parallel letter exercise (#745)
* Fixes to concept tree * Add Parallel Letter Frequency exercise with multi-threading support * Format files * Add Crystal 1.19 new concurrent datatypes * Format files * Apply suggestions from code review Co-authored-by: Ryan Hartlage <2488333+ryanplusplus@users.noreply.github.com> --------- Co-authored-by: Ryan Hartlage <2488333+ryanplusplus@users.noreply.github.com>
1 parent 1d4183f commit d795d0b

9 files changed

Lines changed: 248 additions & 0 deletions

File tree

config.json

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1337,6 +1337,14 @@
13371337
"prerequisites": [],
13381338
"difficulty": 5
13391339
},
1340+
{
1341+
"slug": "parallel-letter-frequency",
1342+
"name": "Parallel Letter Frequency",
1343+
"uuid": "f893d23c-c432-48fd-ae87-0561451cb180",
1344+
"practices": [],
1345+
"prerequisites": [],
1346+
"difficulty": 5
1347+
},
13401348
{
13411349
"slug": "dominoes",
13421350
"name": "Dominoes",
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
# Instruction Appendix
2+
3+
For building a concurrent/parallel program in Crystal, [might this resource prove useful][resource].
4+
In Crystal 1.19 a new [Sync][sync] library was added which adds several primitives to make it easier to make high performance concurrent/parallel programs.
5+
6+
The online environment for this exercise is a bit different from most other exercises.
7+
Instead of compiling Crystal into a single-threaded binary, this exercises uses Crystal's experimental multi-threading capabilities.
8+
As such, the execution might behave differently than expected in some environments.
9+
10+
For local development, it is recommended that you have Crystal version 1.19.0 or later installed, and add `-Dpreview_mt` flag when compiling or running your code to enable multi-threading support.
11+
12+
[resource]: https://crystal-lang.org/reference/latest/guides/concurrency.html
13+
[sync]: https://crystal-lang.org/api/latest/Sync.html
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
# Instructions
2+
3+
Count the frequency of letters in texts using parallel computation.
4+
5+
Parallelism is about doing things in parallel that can also be done sequentially.
6+
A common example is counting the frequency of letters.
7+
Employ parallelism to calculate the total frequency of each letter in a list of texts.
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
{
2+
"authors": [
3+
"meatball133"
4+
],
5+
"files": {
6+
"solution": [
7+
"src/parallel_letter_frequency.cr"
8+
],
9+
"test": [
10+
"spec/parallel_letter_frequency_spec.cr"
11+
],
12+
"example": [
13+
".meta/src/example.cr"
14+
]
15+
},
16+
"blurb": "Count the frequency of letters in texts using parallel computation."
17+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
require "sync/shared"
2+
3+
class ParallelLetterFrequency
4+
def self.calculate_frequencies(input : Array(String)) : Hash(String, Int32)
5+
data : Sync::Shared(Hash(String, Int32)) = Sync::Shared.new({} of String => Int32)
6+
channel = Channel(Nil).new
7+
input.each do |text|
8+
spawn do
9+
local = Hash(String, Int32).new(0)
10+
11+
text.each_char do |char|
12+
next unless char.letter?
13+
local[char.downcase.to_s] += 1
14+
end
15+
16+
data.replace do |shared_data|
17+
local.each do |char, count|
18+
shared_data[char] ||= 0
19+
shared_data[char] += count
20+
end
21+
shared_data
22+
end
23+
channel.send(nil) # signal completion
24+
end
25+
end
26+
27+
input.size.times do
28+
channel.receive
29+
end
30+
31+
data.get
32+
end
33+
end
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
require "spec"
2+
require "../src/*"
3+
4+
describe "<%-= to_capitalized(@json["exercise"].to_s) %>" do
5+
<%- @json["cases"].as_a.each do |cases| %>
6+
<%= status()%> "<%-= cases["description"] %>" do
7+
input = [<%= cases["input"]["texts"].as_a.map { |text| text.to_s.inspect }.join(", ") %>] <%= to_s_deep(cases["input"]["texts"]) == "[]" ? "of String" : ""%>
8+
expected = <%= to_s_deep(cases["expected"]) == "{}" ? "{} of String => Int32" : to_s_deep(cases["expected"]) %>
9+
<%= to_capitalized(@json["exercise"].to_s) %>.<%= cases["property"].to_s.underscore %>(input).should eq(expected)
10+
end
11+
<% end %>
12+
end
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
# This is an auto-generated file.
2+
#
3+
# Regenerating this file via `configlet sync` will:
4+
# - Recreate every `description` key/value pair
5+
# - Recreate every `reimplements` key/value pair, where they exist in problem-specifications
6+
# - Remove any `include = true` key/value pair (an omitted `include` key implies inclusion)
7+
# - Preserve any other key/value pair
8+
#
9+
# As user-added comments (using the # character) will be removed when this file
10+
# is regenerated, comments can be added via a `comment` key.
11+
12+
[c054d642-c1fa-4234-8007-9339f2337886]
13+
description = "no texts"
14+
15+
[818031be-49dc-4675-b2f9-c4047f638a2a]
16+
description = "one text with one letter"
17+
18+
[c0b81d1b-940d-4cea-9f49-8445c69c17ae]
19+
description = "one text with multiple letters"
20+
21+
[708ff1e0-f14a-43fd-adb5-e76750dcf108]
22+
description = "two texts with one letter"
23+
24+
[1b5c28bb-4619-4c9d-8db9-a4bb9c3bdca0]
25+
description = "two texts with multiple letters"
26+
27+
[6366e2b8-b84c-4334-a047-03a00a656d63]
28+
description = "ignore letter casing"
29+
30+
[92ebcbb0-9181-4421-a784-f6f5aa79f75b]
31+
description = "ignore whitespace"
32+
33+
[bc5f4203-00ce-4acc-a5fa-f7b865376fd9]
34+
description = "ignore punctuation"
35+
36+
[68032b8b-346b-4389-a380-e397618f6831]
37+
description = "ignore numbers"
38+
39+
[aa9f97ac-3961-4af1-88e7-6efed1bfddfd]
40+
description = "Unicode letters"
41+
42+
[7b1da046-701b-41fc-813e-dcfb5ee51813]
43+
description = "combination of lower- and uppercase letters, punctuation and white space"
44+
45+
[4727f020-df62-4dcf-99b2-a6e58319cb4f]
46+
description = "large texts"
47+
48+
[adf8e57b-8e54-4483-b6b8-8b32c115884c]
49+
description = "many small texts"

exercises/practice/parallel-letter-frequency/spec/parallel_letter_frequency_spec.cr

Lines changed: 104 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
class ParallelLetterFrequency
2+
def self.calculate_frequencies(input : Array(String)) : Hash(String, Int32)
3+
# Write your code for the 'ParallelLetterFrequency' exercise in this file.
4+
end
5+
end

0 commit comments

Comments
 (0)