Skip to content

Commit 34f38d4

Browse files
authored
add strain (#96)
* add `strain` * Update spec generator
1 parent 752cad4 commit 34f38d4

9 files changed

Lines changed: 295 additions & 0 deletions

File tree

config.json

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,14 @@
194194
"prerequisites": [],
195195
"difficulty": 2
196196
},
197+
{
198+
"slug": "strain",
199+
"name": "Strain",
200+
"uuid": "9fd2db0a-e806-451c-9bea-3d895dccd6f6",
201+
"practices": [],
202+
"prerequisites": [],
203+
"difficulty": 2
204+
},
197205
{
198206
"slug": "sum-of-multiples",
199207
"name": "Sum of Multiples",

exercises/practice/strain/.busted

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
return {
2+
default = {
3+
ROOT = { '.' }
4+
}
5+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
# Instructions
2+
3+
Implement the `keep` and `discard` operation on collections.
4+
Given a collection and a predicate on the collection's elements, `keep` returns a new collection containing those elements where the predicate is true, while `discard` returns a new collection containing those elements where the predicate is false.
5+
6+
For example, given the collection of numbers:
7+
8+
- 1, 2, 3, 4, 5
9+
10+
And the predicate:
11+
12+
- is the number even?
13+
14+
Then your keep operation should produce:
15+
16+
- 2, 4
17+
18+
While your discard operation should produce:
19+
20+
- 1, 3, 5
21+
22+
Note that the union of keep and discard is all the elements.
23+
24+
The functions may be called `keep` and `discard`, or they may need different names in order to not clash with existing functions or concepts in your language.
25+
26+
## Restrictions
27+
28+
Keep your hands off that filter/reject/whatchamacallit functionality provided by your standard library!
29+
Solve this one yourself using other basic tools instead.
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
{
2+
"authors": [
3+
"BNAndras"
4+
],
5+
"files": {
6+
"solution": [
7+
"strain.moon"
8+
],
9+
"test": [
10+
"strain_spec.moon"
11+
],
12+
"example": [
13+
".meta/example.moon"
14+
]
15+
},
16+
"blurb": "Implement the `keep` and `discard` operation on collections.",
17+
"source": "Conversation with James Edward Gray II",
18+
"source_url": "http://graysoftinc.com/"
19+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
keep: (list, predicate) ->
3+
[item for item in *list when predicate(item)]
4+
5+
discard: (list, predicate) ->
6+
[item for item in *list when not predicate(item)]
7+
}
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
format_predicate = (pred) ->
2+
switch pred
3+
when "fn(x) -> true"
4+
"(_) -> true"
5+
when "fn(x) -> false"
6+
"(_) -> false"
7+
when "fn(x) -> x % 2 == 1"
8+
"(num) -> num % 2 == 1"
9+
when "fn(x) -> x % 2 == 0"
10+
"(num) -> num % 2 == 0"
11+
when "fn(x) -> contains(x, 5)"
12+
"(list) -> contains list, 5"
13+
when "fn(x) -> starts_with(x, 'z')"
14+
"(str) -> starts_with str, 'z'"
15+
else
16+
pred
17+
18+
format_list = (list) ->
19+
if #list == 0
20+
"{}"
21+
elseif type(list[1]) == 'string'
22+
"{" .. table.concat([quote(elem) for elem in *list], ', ') .. "}"
23+
else
24+
"{" .. table.concat(list, ', ') .. "}"
25+
26+
format_value = (val, level) ->
27+
if #val == 0
28+
'{}'
29+
elseif type(val[1]) == 'table'
30+
rows = [indent format_list(row), level + 1 for row in *val]
31+
table.insert rows, 1, '{'
32+
table.insert rows, indent('}', level)
33+
table.concat rows, '\n'
34+
else
35+
format_list(val)
36+
37+
{
38+
module_name: 'Strain'
39+
40+
test_helpers: [[
41+
42+
starts_with = (str, prefix) ->
43+
str\sub(1, #prefix) == prefix
44+
45+
contains = (list, element) ->
46+
for item in *list
47+
if item == element
48+
return true
49+
false
50+
]]
51+
52+
generate_test: (case, level) ->
53+
54+
55+
lines = {
56+
"result = Strain.#{case.property} #{format_value(case.input.list, level)}, #{format_predicate case.input.predicate}"
57+
"expected = #{format_value(case.expected, level)}"
58+
"assert.are.same expected, result"
59+
}
60+
61+
table.concat [indent line, level for line in *lines], '\n'
62+
}
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
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+
[26af8c32-ba6a-4eb3-aa0a-ebd8f136e003]
13+
description = "keep on empty list returns empty list"
14+
15+
[f535cb4d-e99b-472a-bd52-9fa0ffccf454]
16+
description = "keeps everything"
17+
18+
[950b8e8e-f628-42a8-85e2-9b30f09cde38]
19+
description = "keeps nothing"
20+
21+
[92694259-6e76-470c-af87-156bdf75018a]
22+
description = "keeps first and last"
23+
24+
[938f7867-bfc7-449e-a21b-7b00cbb56994]
25+
description = "keeps neither first nor last"
26+
27+
[8908e351-4437-4d2b-a0f7-770811e48816]
28+
description = "keeps strings"
29+
30+
[2728036b-102a-4f1e-a3ef-eac6160d876a]
31+
description = "keeps lists"
32+
33+
[ef16beb9-8d84-451a-996a-14e80607fce6]
34+
description = "discard on empty list returns empty list"
35+
36+
[2f42f9bc-8e06-4afe-a222-051b5d8cd12a]
37+
description = "discards everything"
38+
39+
[ca990fdd-08c2-4f95-aa50-e0f5e1d6802b]
40+
description = "discards nothing"
41+
42+
[71595dae-d283-48ca-a52b-45fa96819d2f]
43+
description = "discards first and last"
44+
45+
[ae141f79-f86d-4567-b407-919eaca0f3dd]
46+
description = "discards neither first nor last"
47+
48+
[daf25b36-a59f-4f29-bcfe-302eb4e43609]
49+
description = "discards strings"
50+
51+
[a38d03f9-95ad-4459-80d1-48e937e4acaf]
52+
description = "discards lists"
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
keep: (list, predicate) ->
3+
error 'Implement me'
4+
5+
discard: (list, predicate) ->
6+
error 'Implement me'
7+
}
Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
Strain = require 'strain'
2+
3+
describe 'strain', ->
4+
starts_with = (str, prefix) ->
5+
str\sub(1, #prefix) == prefix
6+
7+
contains = (list, element) ->
8+
for item in *list
9+
if item == element
10+
return true
11+
false
12+
13+
it 'keep on empty list returns empty list', ->
14+
result = Strain.keep {}, (_) -> true
15+
expected = {}
16+
assert.are.same expected, result
17+
18+
pending 'keeps everything', ->
19+
result = Strain.keep {1, 3, 5}, (_) -> true
20+
expected = {1, 3, 5}
21+
assert.are.same expected, result
22+
23+
pending 'keeps nothing', ->
24+
result = Strain.keep {1, 3, 5}, (_) -> false
25+
expected = {}
26+
assert.are.same expected, result
27+
28+
pending 'keeps first and last', ->
29+
result = Strain.keep {1, 2, 3}, (num) -> num % 2 == 1
30+
expected = {1, 3}
31+
assert.are.same expected, result
32+
33+
pending 'keeps neither first nor last', ->
34+
result = Strain.keep {1, 2, 3}, (num) -> num % 2 == 0
35+
expected = {2}
36+
assert.are.same expected, result
37+
38+
pending 'keeps strings', ->
39+
result = Strain.keep {'apple', 'zebra', 'banana', 'zombies', 'cherimoya', 'zealot'}, (str) -> starts_with str, 'z'
40+
expected = {'zebra', 'zombies', 'zealot'}
41+
assert.are.same expected, result
42+
43+
pending 'keeps lists', ->
44+
result = Strain.keep {
45+
{1, 2, 3}
46+
{5, 5, 5}
47+
{5, 1, 2}
48+
{2, 1, 2}
49+
{1, 5, 2}
50+
{2, 2, 1}
51+
{1, 2, 5}
52+
}, (list) -> contains list, 5
53+
expected = {
54+
{5, 5, 5}
55+
{5, 1, 2}
56+
{1, 5, 2}
57+
{1, 2, 5}
58+
}
59+
assert.are.same expected, result
60+
61+
pending 'discard on empty list returns empty list', ->
62+
result = Strain.discard {}, (_) -> true
63+
expected = {}
64+
assert.are.same expected, result
65+
66+
pending 'discards everything', ->
67+
result = Strain.discard {1, 3, 5}, (_) -> true
68+
expected = {}
69+
assert.are.same expected, result
70+
71+
pending 'discards nothing', ->
72+
result = Strain.discard {1, 3, 5}, (_) -> false
73+
expected = {1, 3, 5}
74+
assert.are.same expected, result
75+
76+
pending 'discards first and last', ->
77+
result = Strain.discard {1, 2, 3}, (num) -> num % 2 == 1
78+
expected = {2}
79+
assert.are.same expected, result
80+
81+
pending 'discards neither first nor last', ->
82+
result = Strain.discard {1, 2, 3}, (num) -> num % 2 == 0
83+
expected = {1, 3}
84+
assert.are.same expected, result
85+
86+
pending 'discards strings', ->
87+
result = Strain.discard {'apple', 'zebra', 'banana', 'zombies', 'cherimoya', 'zealot'}, (str) -> starts_with str, 'z'
88+
expected = {'apple', 'banana', 'cherimoya'}
89+
assert.are.same expected, result
90+
91+
pending 'discards lists', ->
92+
result = Strain.discard {
93+
{1, 2, 3}
94+
{5, 5, 5}
95+
{5, 1, 2}
96+
{2, 1, 2}
97+
{1, 5, 2}
98+
{2, 2, 1}
99+
{1, 2, 5}
100+
}, (list) -> contains list, 5
101+
expected = {
102+
{1, 2, 3}
103+
{2, 1, 2}
104+
{2, 2, 1}
105+
}
106+
assert.are.same expected, result

0 commit comments

Comments
 (0)