From 682ca3ec9020e6b262a6799c8138c1343f649035 Mon Sep 17 00:00:00 2001
From: Kevin Marker <kmarker1101@users.noreply.github.com>
Date: Tue, 25 Jun 2024 15:03:51 -0500
Subject: [PATCH] add strain exercise (#423)

---
 config.json                                   |  8 ++
 .../practice/strain/.docs/instructions.md     | 29 +++++++
 exercises/practice/strain/.meta/config.json   | 19 ++++
 exercises/practice/strain/.meta/example.el    | 24 ++++++
 exercises/practice/strain/.meta/tests.toml    | 52 +++++++++++
 exercises/practice/strain/strain-test.el      | 86 +++++++++++++++++++
 exercises/practice/strain/strain.el           | 17 ++++
 7 files changed, 235 insertions(+)
 create mode 100644 exercises/practice/strain/.docs/instructions.md
 create mode 100644 exercises/practice/strain/.meta/config.json
 create mode 100644 exercises/practice/strain/.meta/example.el
 create mode 100644 exercises/practice/strain/.meta/tests.toml
 create mode 100644 exercises/practice/strain/strain-test.el
 create mode 100644 exercises/practice/strain/strain.el

diff --git a/config.json b/config.json
index 65770b9b..7b6c2294 100644
--- a/config.json
+++ b/config.json
@@ -886,6 +886,14 @@
         "practices": [],
         "prerequisites": [],
         "difficulty": 5
+      },
+      {
+        "slug": "strain",
+        "name": "Strain",
+        "uuid": "daff70f7-504a-4ba5-89a5-1a2860dcd98e",
+        "practices": [],
+        "prerequisites": [],
+        "difficulty": 2
       }
     ]
   },
diff --git a/exercises/practice/strain/.docs/instructions.md b/exercises/practice/strain/.docs/instructions.md
new file mode 100644
index 00000000..3469ae65
--- /dev/null
+++ b/exercises/practice/strain/.docs/instructions.md
@@ -0,0 +1,29 @@
+# Instructions
+
+Implement the `keep` and `discard` operation on collections.
+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.
+
+For example, given the collection of numbers:
+
+- 1, 2, 3, 4, 5
+
+And the predicate:
+
+- is the number even?
+
+Then your keep operation should produce:
+
+- 2, 4
+
+While your discard operation should produce:
+
+- 1, 3, 5
+
+Note that the union of keep and discard is all the elements.
+
+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.
+
+## Restrictions
+
+Keep your hands off that filter/reject/whatchamacallit functionality provided by your standard library!
+Solve this one yourself using other basic tools instead.
diff --git a/exercises/practice/strain/.meta/config.json b/exercises/practice/strain/.meta/config.json
new file mode 100644
index 00000000..2165d6b3
--- /dev/null
+++ b/exercises/practice/strain/.meta/config.json
@@ -0,0 +1,19 @@
+{
+  "authors": [
+    "kmarker1101"
+  ],
+  "files": {
+    "solution": [
+      "strain.el"
+    ],
+    "test": [
+      "strain-test.el"
+    ],
+    "example": [
+      ".meta/example.el"
+    ]
+  },
+  "blurb": "Implement the `keep` and `discard` operation on collections.",
+  "source": "Conversation with James Edward Gray II",
+  "source_url": "http://graysoftinc.com/"
+}
diff --git a/exercises/practice/strain/.meta/example.el b/exercises/practice/strain/.meta/example.el
new file mode 100644
index 00000000..7f7f0a41
--- /dev/null
+++ b/exercises/practice/strain/.meta/example.el
@@ -0,0 +1,24 @@
+;;; strain.el --- Strain (exercism)  -*- lexical-binding: t; -*-
+
+;;; Commentary:
+
+;;; Code:
+
+
+(defun keep (predicate list)
+  "Return a list of elements in COLLECTION for which PREDICATE returns true."
+  (let (result)
+    (dolist (element list (nreverse result))
+      (when (funcall predicate element)
+        (push element result)))))
+
+(defun discard (predicate list)
+  "Return a list of elements in COLLECTION for which PREDICATE returns false."
+  (let (result)
+    (dolist (element list (nreverse result))
+      (unless (funcall predicate element)
+        (push element result)))))
+
+
+(provide 'strain)
+;;; strain.el ends here
diff --git a/exercises/practice/strain/.meta/tests.toml b/exercises/practice/strain/.meta/tests.toml
new file mode 100644
index 00000000..3a617b4a
--- /dev/null
+++ b/exercises/practice/strain/.meta/tests.toml
@@ -0,0 +1,52 @@
+# This is an auto-generated file.
+#
+# Regenerating this file via `configlet sync` will:
+# - Recreate every `description` key/value pair
+# - Recreate every `reimplements` key/value pair, where they exist in problem-specifications
+# - Remove any `include = true` key/value pair (an omitted `include` key implies inclusion)
+# - Preserve any other key/value pair
+#
+# As user-added comments (using the # character) will be removed when this file
+# is regenerated, comments can be added via a `comment` key.
+
+[26af8c32-ba6a-4eb3-aa0a-ebd8f136e003]
+description = "keep on empty list returns empty list"
+
+[f535cb4d-e99b-472a-bd52-9fa0ffccf454]
+description = "keeps everything"
+
+[950b8e8e-f628-42a8-85e2-9b30f09cde38]
+description = "keeps nothing"
+
+[92694259-6e76-470c-af87-156bdf75018a]
+description = "keeps first and last"
+
+[938f7867-bfc7-449e-a21b-7b00cbb56994]
+description = "keeps neither first nor last"
+
+[8908e351-4437-4d2b-a0f7-770811e48816]
+description = "keeps strings"
+
+[2728036b-102a-4f1e-a3ef-eac6160d876a]
+description = "keeps lists"
+
+[ef16beb9-8d84-451a-996a-14e80607fce6]
+description = "discard on empty list returns empty list"
+
+[2f42f9bc-8e06-4afe-a222-051b5d8cd12a]
+description = "discards everything"
+
+[ca990fdd-08c2-4f95-aa50-e0f5e1d6802b]
+description = "discards nothing"
+
+[71595dae-d283-48ca-a52b-45fa96819d2f]
+description = "discards first and last"
+
+[ae141f79-f86d-4567-b407-919eaca0f3dd]
+description = "discards neither first nor last"
+
+[daf25b36-a59f-4f29-bcfe-302eb4e43609]
+description = "discards strings"
+
+[a38d03f9-95ad-4459-80d1-48e937e4acaf]
+description = "discards lists"
diff --git a/exercises/practice/strain/strain-test.el b/exercises/practice/strain/strain-test.el
new file mode 100644
index 00000000..b73d08e5
--- /dev/null
+++ b/exercises/practice/strain/strain-test.el
@@ -0,0 +1,86 @@
+;;; strain-test.el --- Strain (exercism)  -*- lexical-binding: t; -*-
+
+;;; Commentary:
+
+;;; Code:
+
+
+(load-file "strain.el")
+(declare-function keep "strain.el" (predicate list))
+(declare-function discard "strain.el" (predicate list))
+
+
+(defun starts-with (string prefix)
+  (string-prefix-p prefix string))
+
+
+(defun contains (list element)
+  (member element list))
+
+
+(ert-deftest keep-on-empty-list-returns-empty-list ()
+  (should (equal (keep (lambda (x) t) '()) '())))
+
+
+(ert-deftest keeps-everything ()
+  (should (equal (keep (lambda (x) t) '(1 3 5)) '(1 3 5))))
+
+
+(ert-deftest keeps-nothing ()
+  (should (equal (keep (lambda (x) nil) '(1 3 5)) '())))
+
+
+(ert-deftest keeps-first-and-last ()
+  (should (equal (keep (lambda (x) (= 1 (% x 2))) '(1 2 3)) '(1 3))))
+
+
+(ert-deftest keeps-neither-first-nor-last ()
+  (should (equal (keep (lambda (x) (= 0 (% x 2))) '(1 2 3)) '(2))))
+
+
+(ert-deftest keeps-strings ()
+  (should (equal (keep (lambda (x) (starts-with x "z"))
+                       '("apple" "zebra" "banana" "zombies" "cherimoya" "zealot"))
+                 '("zebra" "zombies" "zealot"))))
+
+
+(ert-deftest keeps-lists ()
+  (should (equal (keep (lambda (x) (contains x 5))
+                       '((1 2 3) (5 5 5) (5 1 2) (2 1 2) (1 5 2) (2 2 1) (1 2 5)))
+                 '((5 5 5) (5 1 2) (1 5 2) (1 2 5)))))
+
+
+(ert-deftest discard-on-empty-list-returns-empty-list ()
+  (should (equal (discard (lambda (x) t) '()) '())))
+
+
+(ert-deftest discards-everything ()
+  (should (equal (discard (lambda (x) t) '(1 3 5)) '())))
+
+
+(ert-deftest discards-nothing ()
+  (should (equal (discard (lambda (x) nil) '(1 3 5)) '(1 3 5))))
+
+
+(ert-deftest discards-first-and-last ()
+  (should (equal (discard (lambda (x) (= (mod x 2) 1)) '(1 2 3)) '(2))))
+
+
+(ert-deftest discards-neither-first-nor-last ()
+  (should (equal (discard (lambda (x) (= (mod x 2) 0)) '(1 2 3)) '(1 3))))
+
+
+(ert-deftest discards-strings ()
+  (should (equal (discard (lambda (x) (starts-with x "z"))
+                          '("apple" "zebra" "banana" "zombies" "cherimoya" "zealot"))
+                 '("apple" "banana" "cherimoya"))))
+
+
+(ert-deftest discards-lists ()
+  (should (equal (discard (lambda (x) (contains x 5))
+                          '((1 2 3) (5 5 5) (5 1 2) (2 1 2) (1 5 2) (2 2 1) (1 2 5)))
+                 '((1 2 3) (2 1 2) (2 2 1)))))
+
+
+(provide 'strain-test)
+;;; strain-test.el ends here
diff --git a/exercises/practice/strain/strain.el b/exercises/practice/strain/strain.el
new file mode 100644
index 00000000..457ccbb3
--- /dev/null
+++ b/exercises/practice/strain/strain.el
@@ -0,0 +1,17 @@
+;;; strain.el --- Strain (exercism)  -*- lexical-binding: t; -*-
+
+;;; Commentary:
+
+;;; Code:
+
+
+(defun keep (predicate list)
+  (error "Delete this S-Expression and write your own implementation"))
+
+(defun discard (predicate list)
+  (error "Delete this S-Expression and write your own implementation"))
+
+
+(provide 'strain)
+;;; strain.el ends here
+