diff --git a/config.json b/config.json index e51ab4d6..ab0bbf84 100644 --- a/config.json +++ b/config.json @@ -997,6 +997,14 @@ "strings" ] }, + { + "slug": "strain", + "name": "Strain", + "uuid": "8872a713-cb44-4769-a67b-85bbd944a726", + "practices": [], + "prerequisites": [], + "difficulty": 2 + }, { "slug": "pig-latin", "name": "Pig Latin", 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..896eef91 --- /dev/null +++ b/exercises/practice/strain/.meta/config.json @@ -0,0 +1,19 @@ +{ + "authors": [ + "tomasnorre" + ], + "files": { + "solution": [ + "Strain.php" + ], + "test": [ + "StrainTest.php" + ], + "example": [ + ".meta/example.php" + ] + }, + "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.php b/exercises/practice/strain/.meta/example.php new file mode 100644 index 00000000..529d0347 --- /dev/null +++ b/exercises/practice/strain/.meta/example.php @@ -0,0 +1,27 @@ +filter($list, $predicate, true); + } + + public function discard(array $list, callable $predicate): array + { + return $this->filter($list, $predicate, false); + } + + private function filter(array $list, callable $predicate, bool $keepMatches): array + { + $results = []; + foreach ($list as $item) { + if ($predicate($item) === $keepMatches) { + $results[] = $item; + } + } + return $results; + } +} 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.php b/exercises/practice/strain/Strain.php new file mode 100644 index 00000000..803b4957 --- /dev/null +++ b/exercises/practice/strain/Strain.php @@ -0,0 +1,38 @@ +. + * + * To disable strict typing, comment out the directive below. + */ + +declare(strict_types=1); + +class Strain +{ + public function keep(array $list, callable $predicate): array + { + throw new \BadMethodCallException(sprintf('Implement the %s method', __FUNCTION__)); + } + + public function discard(array $list, callable $predicate): array + { + throw new \BadMethodCallException(sprintf('Implement the %s method', __FUNCTION__)); + } +} diff --git a/exercises/practice/strain/StrainTest.php b/exercises/practice/strain/StrainTest.php new file mode 100644 index 00000000..dbe47996 --- /dev/null +++ b/exercises/practice/strain/StrainTest.php @@ -0,0 +1,229 @@ +strain = new Strain(); + } + + /** + * uuid: 26af8c32-ba6a-4eb3-aa0a-ebd8f136e003 + */ + public function testKeepOnEmptyListReturnsEmptyList(): void + { + $list = []; + $predicate = function ($x) { + return true; + }; + + $this->assertEquals([], $this->strain->keep($list, $predicate)); + } + + /** + * uuid: f535cb4d-e99b-472a-bd52-9fa0ffccf454 + */ + public function testKeepsEverything(): void + { + $list = [1, 3, 5]; + $predicate = function ($x) { + return true; + }; + + $this->assertEquals([1, 3, 5], $this->strain->keep($list, $predicate)); + } + + /** + * uuid: 950b8e8e-f628-42a8-85e2-9b30f09cde38 + */ + public function testKeepNothing(): void + { + $list = [1, 3, 5]; + $predicate = function ($x) { + return false; + }; + + $this->assertEquals([], $this->strain->keep($list, $predicate)); + } + + /** + * uuid: 92694259-6e76-470c-af87-156bdf75018a + */ + public function testKeepFirstAndLast(): void + { + $list = [1, 2, 3]; + $predicate = function ($x) { + return $x % 2 === 1; + }; + + $this->assertEquals([1, 3], $this->strain->keep($list, $predicate)); + } + + /** + * uuid: 938f7867-bfc7-449e-a21b-7b00cbb56994 + */ + public function testKeepNeitherFirstNorLast(): void + { + $list = [1, 2, 3]; + $predicate = function ($x) { + return $x % 2 === 0; + }; + + $this->assertEquals([2], $this->strain->keep($list, $predicate)); + } + + /** + * uuid: 8908e351-4437-4d2b-a0f7-770811e4881 + */ + public function testKeepStrings(): void + { + $list = ["apple", "zebra", "banana", "zombies", "cherimoya", "zealot"]; + $predicate = function ($x) { + return str_starts_with($x, 'z'); + }; + + $this->assertEquals(["zebra", "zombies", "zealot"], $this->strain->keep($list, $predicate)); + } + + /** + * uuid: 2728036b-102a-4f1e-a3ef-eac6160d876a + */ + public function testKeepsLists(): void + { + $list = [ + [1, 2, 3], + [5, 5, 5], + [5, 1, 2], + [2, 1, 2], + [1, 5, 2], + [2, 2, 1], + [1, 2, 5] + ]; + $predicate = function ($x) { + return in_array(5, $x, true); + }; + + $expected = [ + [5, 5, 5], + [5, 1, 2], + [1, 5, 2], + [1, 2, 5] + ]; + + $this->assertEquals($expected, $this->strain->keep($list, $predicate)); + } + + /** + * uuid: ef16beb9-8d84-451a-996a-14e80607fce6 + */ + public function testDiscardOnEmptyListReturnsEmptyList(): void + { + $list = []; + $predicate = function ($x) { + return true; + }; + + $this->assertEquals([], $this->strain->discard($list, $predicate)); + } + + /** + * uuid: 2f42f9bc-8e06-4afe-a222-051b5d8cd12a + */ + public function testDiscardEverything(): void + { + $list = [1, 3, 5]; + $predicate = function ($x) { + return true; + }; + + $this->assertEquals([], $this->strain->discard($list, $predicate)); + } + + /** + * uuid: ca990fdd-08c2-4f95-aa50-e0f5e1d6802b + */ + public function testDiscardNothing(): void + { + $list = [1, 3, 5]; + $predicate = function ($x) { + return false; + }; + + $this->assertEquals([1, 3, 5], $this->strain->discard($list, $predicate)); + } + + /** + * uuid: 71595dae-d283-48ca-a52b-45fa96819d2f + */ + public function testDiscardFirstAndLast(): void + { + $list = [1, 2, 3]; + $predicate = function ($x) { + return $x % 2 === 1; + }; + + $this->assertEquals([2], $this->strain->discard($list, $predicate)); + } + + /** + * uuid: ae141f79-f86d-4567-b407-919eaca0f3dd + */ + public function testDiscardNeitherFirstNorLast(): void + { + $list = [1, 2, 3]; + $predicate = function ($x) { + return $x % 2 === 0; + }; + + $this->assertEquals([1,3], $this->strain->discard($list, $predicate)); + } + + /** + * uuid: daf25b36-a59f-4f29-bcfe-302eb4e43609 + */ + public function testDiscardStrings(): void + { + $list = ["apple", "zebra", "banana", "zombies", "cherimoya", "zealot"]; + $predicate = function ($x) { + return str_starts_with($x, 'z'); + }; + + $this->assertEquals(["apple", "banana", "cherimoya"], $this->strain->discard($list, $predicate)); + } + + /** + * uuid: a38d03f9-95ad-4459-80d1-48e937e4acaf + */ + public function testDiscardLists(): void + { + $list = [ + [1, 2, 3], + [5, 5, 5], + [5, 1, 2], + [2, 1, 2], + [1, 5, 2], + [2, 2, 1], + [1, 2, 5] + ]; + $predicate = function ($x) { + return in_array(5, $x, true); + }; + + $expected = [ + [1, 2, 3], + [2, 1, 2], + [2, 2, 1] + ]; + + $this->assertEquals($expected, $this->strain->discard($list, $predicate)); + } +}