Skip to content

Commit d0685c9

Browse files
committed
step-by-step
1 parent 4bc6253 commit d0685c9

File tree

4 files changed

+121
-1
lines changed

4 files changed

+121
-1
lines changed

exercises/practice/raindrops/.approaches/config.json

+7
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,13 @@
66
"title": "Pattern Matching",
77
"blurb": "",
88
"authors": []
9+
},
10+
{
11+
"uuid": "925ccb59-3414-472b-9054-1cdfc5e44fad",
12+
"slug": "step-by-step",
13+
"title": "Step By Step",
14+
"blurb": "",
15+
"authors": []
916
}
1017
]
1118
}

exercises/practice/raindrops/.approaches/introduction.md

+25-1
Original file line numberDiff line numberDiff line change
@@ -22,4 +22,28 @@ end
2222

2323
We can use a few Elixir features to do more or less the same and we explore them in the [pattern matching approach][pattern-matching-approach].
2424

25-
[pattern-matching-approach]: https://exercism.org/tracks/elixir/exercises/raindrops/approaches/pattern-matching
25+
## Step by step
26+
27+
An alternative approach is to consider each condition one at a time.
28+
At each step we return either a sound (i.e. "Pling", "Plang", or "Plong"), or an empty string.
29+
We can then concatenate the strings together.
30+
31+
```elixir
32+
def convert(number) do
33+
pling = if rem(number, 3) == 0, do: "Pling", else: ""
34+
plang = if rem(number, 5) == 0, do: "Plang", else: ""
35+
plong = if rem(number, 7) == 0, do: "Plong", else: ""
36+
result = pling <> plang <> plong
37+
38+
if result == "" do
39+
Integer.to_string(number)
40+
else
41+
result
42+
end
43+
end
44+
```
45+
46+
Let's have a look at a few variations of this [step by step approach][step-by-step-approach].
47+
48+
[pattern-matching-approach]: https://exercism.org/tracks/elixir/exercises/raindrops/approaches/pattern-matching
49+
[step-by-step-approach]: https://exercism.org/tracks/elixir/exercises/raindrops/approaches/step-by-step
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
# Step By Step
2+
3+
```elixir
4+
defmodule Raindrops do
5+
@spec convert(pos_integer) :: String.t()
6+
def convert(number) do
7+
pling = if rem(number, 3) == 0, do: "Pling", else: ""
8+
plang = if rem(number, 5) == 0, do: "Plang", else: ""
9+
plong = if rem(number, 7) == 0, do: "Plong", else: ""
10+
sound = pling <> plang <> plong
11+
12+
if sound == "" do
13+
Integer.to_string(number)
14+
else
15+
sound
16+
end
17+
end
18+
end
19+
```
20+
21+
In this approach, we test each condition only once, similar to using the `case` on a tuple in the [pattern matching approach][pattern-matching-approach].
22+
However, this time, if a condition is true, we capture the sound component, and if it is not true, we capture the sound as an empty string.
23+
24+
Once this is done, we can concatenate all three conditions to get the full sound.
25+
Finally, if the `sound` is empty, we can return the number or, alternatively, the calculated `sound`.
26+
27+
## Functions
28+
29+
We can create private functions to test for component sounds.
30+
31+
```elixir
32+
defp pling(n) when rem(n, 3) == 0, do: "Pling"
33+
defp pling(_), do: ""
34+
defp plang(n) when rem(n, 5) == 0, do: "Plang"
35+
defp plang(_), do: ""
36+
defp plong(n) when rem(n, 7) == 0, do: "Plong"
37+
defp plong(_), do: ""
38+
defp sound(sound, number) when sound == "", do: Integer.to_string(number)
39+
defp sound(sound, _number), do: sound
40+
```
41+
42+
Now the solution can look like this:
43+
```elixir
44+
def convert(number) do
45+
sound(pling(number) <> plang(number) <> plong(number), number)
46+
end
47+
```
48+
49+
## The pipe operator
50+
51+
With a slightly different design of the functions we can use the pipe operator to have a very clean-looking code
52+
53+
```elixir
54+
@spec convert(pos_integer) :: String.t()
55+
def convert(number) do
56+
{"", number}
57+
|> pling
58+
|> plang
59+
|> plong
60+
|> sound
61+
end
62+
```
63+
At least in the `convert` functions. The `pling`, `plang`, `plong` become a bit more complex:
64+
```elixir
65+
defp pling({ s, n }) when rem(n, 3) == 0, do: { s <> "Pling", n }
66+
defp pling({ s, n }), do: { s, n }
67+
defp plang({ s, n }) when rem(n, 5) == 0, do: { s <> "Plang", n }
68+
defp plang({ s, n }), do: { s, n }
69+
defp plong({ s, n }) when rem(n, 7) == 0, do: { s <> "Plong", n }
70+
defp plong({ s, n }), do: { s, n }
71+
defp sound({ s, n }) when s == "" , do: n |> Integer.to_string
72+
defp sound({ s, _ }), do: s
73+
```
74+
75+
All the examples above, at their core, represent the same approach of doing the check step by step.
76+
77+
[pattern-matching-approach]: https://exercism.org/tracks/elixir/exercises/raindrops/approaches/pattern-matching
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
def convert(number) do
2+
pling = if rem(number, 3) == 0, do: "Pling", else: ""
3+
plang = if rem(number, 5) == 0, do: "Plang", else: ""
4+
plong = if rem(number, 7) == 0, do: "Plong", else: ""
5+
result = pling <> plang <> plong
6+
7+
if result == "" do
8+
Integer.to_string(number)
9+
else
10+
result
11+
end
12+
end

0 commit comments

Comments
 (0)