From 081276ccb716713452a977b171afffa21b192334 Mon Sep 17 00:00:00 2001 From: Kah Goh Date: Fri, 1 Mar 2024 21:29:45 +0800 Subject: [PATCH 01/12] Add list-ops exercise Co-authored-by: Bobby Towers --- config.json | 649 +++++++++++++----- .../practice/list-ops/.docs/instructions.md | 19 + exercises/practice/list-ops/.meta/config.json | 20 + .../practice/list-ops/.meta/src/example.clj | 33 + exercises/practice/list-ops/.meta/tests.toml | 106 +++ exercises/practice/list-ops/deps.edn | 6 + exercises/practice/list-ops/project.clj | 4 + exercises/practice/list-ops/src/list_ops.clj | 33 + .../practice/list-ops/test/list_ops_test.clj | 65 ++ generator.clj | 140 ---- 10 files changed, 781 insertions(+), 294 deletions(-) create mode 100644 exercises/practice/list-ops/.docs/instructions.md create mode 100644 exercises/practice/list-ops/.meta/config.json create mode 100644 exercises/practice/list-ops/.meta/src/example.clj create mode 100644 exercises/practice/list-ops/.meta/tests.toml create mode 100644 exercises/practice/list-ops/deps.edn create mode 100644 exercises/practice/list-ops/project.clj create mode 100644 exercises/practice/list-ops/src/list_ops.clj create mode 100644 exercises/practice/list-ops/test/list_ops_test.clj delete mode 100644 generator.clj diff --git a/config.json b/config.json index 698bace5c..9bbb00990 100644 --- a/config.json +++ b/config.json @@ -26,7 +26,7 @@ "test/%{snake_slug}_test.clj" ], "example": [ - "src/example.clj" + ".meta/src/example.clj" ], "exemplar": [ ".meta/exemplar.clj" @@ -122,7 +122,9 @@ "sequential-destructuring" ], "prerequisites": [ - "lists", "vectors", "strings" + "lists", + "vectors", + "strings" ], "status": "beta" }, @@ -138,8 +140,13 @@ "slug": "squeaky-clean", "name": "Squeaky Clean", "uuid": "3af5b219-d751-4243-89f7-c8f05216f534", - "concepts": ["chars"], - "prerequisites": ["basics", "strings"], + "concepts": [ + "chars" + ], + "prerequisites": [ + "basics", + "strings" + ], "status": "beta" }, { @@ -154,16 +161,27 @@ "slug": "coordinate-transformation", "name": "Coordinate Transformation", "uuid": "5b23eabd-6ebb-4fed-b889-9324ad174a5f", - "concepts": ["closures", "atoms"], - "prerequisites": ["vectors"], + "concepts": [ + "closures", + "atoms" + ], + "prerequisites": [ + "vectors" + ], "status": "beta" }, { "slug": "card-games", "name": "Card Games", "uuid": "01a06d2b-ffb1-4497-9bb3-d93ee2d0931b", - "concepts": ["lists"], - "prerequisites": ["basics", "conditionals", "booleans"], + "concepts": [ + "lists" + ], + "prerequisites": [ + "basics", + "conditionals", + "booleans" + ], "status": "beta" } ], @@ -172,17 +190,24 @@ "slug": "two-fer", "name": "Two Fer", "uuid": "1706ec00-9e51-45d1-ac3e-01b0360ea950", - "practices": ["strings"], - "prerequisites": ["strings"], - "difficulty": 1, - "topics": null + "practices": [ + "strings" + ], + "prerequisites": [ + "strings" + ], + "difficulty": 1 }, { "slug": "armstrong-numbers", "name": "Armstrong Numbers", "uuid": "0e0fec77-651a-45a7-af99-a768ebebef05", - "practices": ["numbers"], - "prerequisites": ["numbers"], + "practices": [ + "numbers" + ], + "prerequisites": [ + "numbers" + ], "difficulty": 1, "topics": [ "math" @@ -204,10 +229,13 @@ "name": "Reverse String", "uuid": "0f7b1858-15d0-467d-9f94-56408249c2f7", "practices": [], - "prerequisites": ["strings"], + "prerequisites": [ + "strings" + ], "difficulty": 1, "topics": [ - "strings", "core_functions" + "strings", + "core_functions" ] }, { @@ -215,7 +243,9 @@ "name": "Accumulate", "uuid": "49f62bbc-0f60-4922-b5a6-f266b80442f4", "practices": [], - "prerequisites": ["numbers"], + "prerequisites": [ + "numbers" + ], "difficulty": 2, "topics": [ "algorithms, core_functions" @@ -225,19 +255,30 @@ "slug": "acronym", "name": "Acronym", "uuid": "b99ed7da-98a8-43f0-8162-05c5408f6ac5", - "practices": ["strings"], - "prerequisites": ["strings", "booleans"], + "practices": [ + "strings" + ], + "prerequisites": [ + "strings", + "booleans" + ], "difficulty": 2, "topics": [ - "strings", "regular_expressions" + "strings", + "regular_expressions" ] }, { "slug": "all-your-base", "name": "All Your Base", "uuid": "7b8c5f7e-3c7d-4e69-ba8c-f29bb492a628", - "practices": ["numbers"], - "prerequisites": ["numbers", "vectors"], + "practices": [ + "numbers" + ], + "prerequisites": [ + "numbers", + "vectors" + ], "difficulty": 2, "topics": [ "math" @@ -247,8 +288,13 @@ "slug": "anagram", "name": "Anagram", "uuid": "11818959-7e42-4a1d-8dfd-288cea744d66", - "practices": ["strings"], - "prerequisites": ["strings", "vectors"], + "practices": [ + "strings" + ], + "prerequisites": [ + "strings", + "vectors" + ], "difficulty": 2, "topics": [ "strings" @@ -258,19 +304,31 @@ "slug": "bob", "name": "Bob", "uuid": "0317cc62-dd75-4841-86c3-01c055630fe7", - "practices": ["conditionals"], - "prerequisites": ["conditionals", "strings"], + "practices": [ + "conditionals" + ], + "prerequisites": [ + "conditionals", + "strings" + ], "difficulty": 2, "topics": [ - "strings", "regular_expressions", "conditionals" + "strings", + "regular_expressions", + "conditionals" ] }, { "slug": "collatz-conjecture", "name": "Collatz Conjecture", "uuid": "9516323c-721e-4bfc-84df-9bc32e467197", - "practices": ["numbers"], - "prerequisites": ["numbers", "conditionals"], + "practices": [ + "numbers" + ], + "prerequisites": [ + "numbers", + "conditionals" + ], "difficulty": 2, "topics": [ "math" @@ -280,8 +338,12 @@ "slug": "complex-numbers", "name": "Complex Numbers", "uuid": "ceaacb97-9c2c-43db-a9ac-28ebe6650f47", - "practices": ["numbers"], - "prerequisites": ["numbers"], + "practices": [ + "numbers" + ], + "prerequisites": [ + "numbers" + ], "difficulty": 2, "topics": [ "math" @@ -292,10 +354,15 @@ "name": "ETL", "uuid": "befca7ee-fc29-4ef0-afd7-2d3f68aa47fb", "practices": [], - "prerequisites": ["lists", "numbers", "strings"], + "prerequisites": [ + "lists", + "numbers", + "strings" + ], "difficulty": 2, "topics": [ - "integers", "maps" + "integers", + "maps" ] }, { @@ -303,18 +370,27 @@ "name": "Hamming", "uuid": "d120ad9a-98e9-4de7-9cb6-6aef3101cd1c", "practices": [], - "prerequisites": ["numbers", "strings", "conditionals"], + "prerequisites": [ + "numbers", + "strings", + "conditionals" + ], "difficulty": 2, "topics": [ - "strings", "conditionals" + "strings", + "conditionals" ] }, { "slug": "nth-prime", "name": "Nth Prime", "uuid": "167113f2-b015-4c04-809d-670193758c25", - "practices": ["numbers"], - "prerequisites": ["numbers"], + "practices": [ + "numbers" + ], + "prerequisites": [ + "numbers" + ], "difficulty": 2, "topics": [ "math" @@ -325,40 +401,61 @@ "name": "Nucleotide Count", "uuid": "223d10d6-539d-441f-89ba-77f7743e6092", "practices": [], - "prerequisites": ["strings", "conditionals"], + "prerequisites": [ + "strings", + "conditionals" + ], "difficulty": 2, "topics": [ - "strings", "conditionals", "exception_handling" + "strings", + "conditionals", + "exception_handling" ] }, { "slug": "pangram", "name": "Pangram", "uuid": "1f96161b-c83a-4f66-bc50-3e32e035da1f", - "practices": ["strings"], - "prerequisites": ["strings", "booleans"], + "practices": [ + "strings" + ], + "prerequisites": [ + "strings", + "booleans" + ], "difficulty": 2, "topics": [ - "strings", "maps" + "strings", + "maps" ] }, { "slug": "pig-latin", "name": "Pig Latin", "uuid": "a9b08dfd-3555-46bc-bc54-d605fd225c34", - "practices": ["strings"], - "prerequisites": ["strings"], + "practices": [ + "strings" + ], + "prerequisites": [ + "strings" + ], "difficulty": 2, "topics": [ - "strings", "regular_expressions" + "strings", + "regular_expressions" ] }, { "slug": "protein-translation", "name": "Protein Translation", "uuid": "591c3cc5-0d14-400d-85a2-4ce0e399813e", - "practices": ["strings"], - "prerequisites": ["strings", "vectors"], + "practices": [ + "strings" + ], + "prerequisites": [ + "strings", + "vectors" + ], "difficulty": 2, "topics": [ "pattern_matching", @@ -369,11 +466,19 @@ "slug": "raindrops", "name": "Raindrops", "uuid": "e670c978-8b71-4880-a543-3f9fb28d88b3", - "practices": ["conditionals"], - "prerequisites": ["numbers", "strings", "conditionals"], + "practices": [ + "conditionals" + ], + "prerequisites": [ + "numbers", + "strings", + "conditionals" + ], "difficulty": 2, "topics": [ - "integers", "strings", "conditionals" + "integers", + "strings", + "conditionals" ] }, { @@ -381,10 +486,13 @@ "name": "RNA Transcription", "uuid": "d8773153-d717-43f1-9324-c7e8cf00455c", "practices": [], - "prerequisites": ["strings"], + "prerequisites": [ + "strings" + ], "difficulty": 2, "topics": [ - "strings", "pattern_matching" + "strings", + "pattern_matching" ] }, { @@ -392,10 +500,16 @@ "name": "Robot Name", "uuid": "ce7df719-d3e2-444f-8ae3-f81c89fd15ce", "practices": [], - "prerequisites": ["numbers", "strings"], + "prerequisites": [ + "numbers", + "strings" + ], "difficulty": 2, "topics": [ - "sets", "conditionals", "regular_expressions", "randomness" + "sets", + "conditionals", + "regular_expressions", + "randomness" ] }, { @@ -403,7 +517,10 @@ "name": "Roman Numerals", "uuid": "cad43fab-50c2-470e-8364-6592e971d4df", "practices": [], - "prerequisites": ["numbers", "strings"], + "prerequisites": [ + "numbers", + "strings" + ], "difficulty": 2, "topics": [ "conditionals" @@ -414,10 +531,14 @@ "name": "Rotational Cipher", "uuid": "a40e8d4b-9793-4991-87d8-7efb92a3e3f2", "practices": [], - "prerequisites": ["numbers", "strings"], + "prerequisites": [ + "numbers", + "strings" + ], "difficulty": 2, "topics": [ - "algorithms", "regular_expressions" + "algorithms", + "regular_expressions" ] }, { @@ -425,10 +546,15 @@ "name": "Run-Length Encoding", "uuid": "fa1be98f-59b2-487e-948d-46e744d50dc4", "practices": [], - "prerequisites": ["numbers", "strings"], + "prerequisites": [ + "numbers", + "strings" + ], "difficulty": 2, "topics": [ - "strings", "regular_expressions", "parsing" + "strings", + "regular_expressions", + "parsing" ] }, { @@ -436,10 +562,14 @@ "name": "Scrabble Score", "uuid": "2804d2d1-0029-4473-8431-0857d4767d91", "practices": [], - "prerequisites": ["numbers", "strings"], + "prerequisites": [ + "numbers", + "strings" + ], "difficulty": 2, "topics": [ - "maps", "strings" + "maps", + "strings" ] }, { @@ -447,10 +577,15 @@ "name": "Secret Handshake", "uuid": "9c270d52-b1fe-4f1a-a639-2f7347c7cb92", "practices": [], - "prerequisites": ["numbers", "vectors", "strings"], + "prerequisites": [ + "numbers", + "vectors", + "strings" + ], "difficulty": 2, "topics": [ - "algorithms", "conditionals" + "algorithms", + "conditionals" ] }, { @@ -458,7 +593,10 @@ "name": "Series", "uuid": "f342d3f2-775f-4fb6-93c2-9aea4a8f5f22", "practices": [], - "prerequisites": ["numbers", "vectors"], + "prerequisites": [ + "numbers", + "vectors" + ], "difficulty": 2, "topics": [ "strings" @@ -468,8 +606,13 @@ "slug": "space-age", "name": "Space Age", "uuid": "c97868e9-36ca-4d00-9483-0fc6b4c37231", - "practices": ["floating-point-numbers"], - "prerequisites": ["numbers", "floating-point-numbers"], + "practices": [ + "floating-point-numbers" + ], + "prerequisites": [ + "numbers", + "floating-point-numbers" + ], "difficulty": 2, "topics": [ "math" @@ -480,18 +623,27 @@ "name": "Strain", "uuid": "8db4904c-a46f-4886-b214-0cf06b0f2ff1", "practices": [], - "prerequisites": ["conditionals", "numbers"], + "prerequisites": [ + "conditionals", + "numbers" + ], "difficulty": 2, "topics": [ - "algorithms", "conditionals", "filtering" + "algorithms", + "conditionals", + "filtering" ] }, { "slug": "sublist", "name": "Sublist", "uuid": "85dc1645-8424-45f2-8653-bc9730887b40", - "practices": ["lists"], - "prerequisites": ["lists"], + "practices": [ + "lists" + ], + "prerequisites": [ + "lists" + ], "difficulty": 2, "topics": [ "sets" @@ -502,7 +654,10 @@ "name": "Sum of Multiples", "uuid": "357de34a-c149-4a2c-b6a8-86ffb5eaa152", "practices": [], - "prerequisites": ["numbers", "conditionals"], + "prerequisites": [ + "numbers", + "conditionals" + ], "difficulty": 2, "topics": [ "math" @@ -512,11 +667,18 @@ "slug": "triangle", "name": "Triangle", "uuid": "a148a999-76ef-40d4-8bf7-96d6ae38876e", - "practices": ["floating-point-numbers", "conditionals"], - "prerequisites": ["floating-point-numbers", "conditionals"], + "practices": [ + "floating-point-numbers", + "conditionals" + ], + "prerequisites": [ + "floating-point-numbers", + "conditionals" + ], "difficulty": 2, "topics": [ - "integers", "conditionals" + "integers", + "conditionals" ] }, { @@ -524,10 +686,15 @@ "name": "Word Count", "uuid": "ea3cf3f6-35de-4da1-a74f-b7a13d89c39a", "practices": [], - "prerequisites": ["numbers", "conditionals", "strings"], + "prerequisites": [ + "numbers", + "conditionals", + "strings" + ], "difficulty": 2, "topics": [ - "regular_expressions", "strings" + "regular_expressions", + "strings" ] }, { @@ -535,10 +702,15 @@ "name": "Atbash Cipher", "uuid": "7d37e817-d2b7-4554-8885-b02d57d1d788", "practices": [], - "prerequisites": ["numbers", "conditionals", "strings"], + "prerequisites": [ + "numbers", + "conditionals", + "strings" + ], "difficulty": 3, "topics": [ - "algorithms", "regular_expressions" + "algorithms", + "regular_expressions" ] }, { @@ -546,10 +718,15 @@ "name": "Beer Song", "uuid": "56a4b06b-c48f-4a0f-883a-a08886472b56", "practices": [], - "prerequisites": ["numbers", "conditionals", "strings"], + "prerequisites": [ + "numbers", + "conditionals", + "strings" + ], "difficulty": 3, "topics": [ - "strings", "conditionals" + "strings", + "conditionals" ] }, { @@ -557,7 +734,9 @@ "name": "Binary", "uuid": "daf3daed-61ef-4964-8d33-e7a739c7a470", "practices": [], - "prerequisites": ["numbers"], + "prerequisites": [ + "numbers" + ], "difficulty": 3, "topics": [ "math" @@ -568,10 +747,14 @@ "name": "Binary Search", "uuid": "f32c6a4b-0f23-4cd2-95b2-f6e70e4b40b1", "practices": [], - "prerequisites": ["vectors"], + "prerequisites": [ + "vectors" + ], "difficulty": 3, "topics": [ - "algorithms", "recursion", "conditionals" + "algorithms", + "recursion", + "conditionals" ] }, { @@ -579,10 +762,13 @@ "name": "Binary Search Tree", "uuid": "53678d3d-de3f-483d-9f02-d2313290786d", "practices": [], - "prerequisites": ["vectors"], + "prerequisites": [ + "vectors" + ], "difficulty": 3, "topics": [ - "algorithms", "recursion" + "algorithms", + "recursion" ] }, { @@ -590,7 +776,10 @@ "name": "Change", "uuid": "7945eb6a-20eb-489d-90bd-020df3d9e2cb", "practices": [], - "prerequisites": ["numbers", "vectors"], + "prerequisites": [ + "numbers", + "vectors" + ], "difficulty": 3, "topics": [ "algorithms" @@ -601,10 +790,13 @@ "name": "Flatten Array", "uuid": "6b81cf43-e071-4daf-89a9-d10e213a5751", "practices": [], - "prerequisites": ["vectors"], + "prerequisites": [ + "vectors" + ], "difficulty": 3, "topics": [ - "core_functions", "seqs" + "core_functions", + "seqs" ] }, { @@ -612,7 +804,9 @@ "name": "Gigasecond", "uuid": "798445d8-acad-4b01-b471-3809f46a8a84", "practices": [], - "prerequisites": ["numbers"], + "prerequisites": [ + "numbers" + ], "difficulty": 3, "topics": [ "time" @@ -623,10 +817,14 @@ "name": "Grade School", "uuid": "a48ff289-baf0-4b13-a5aa-78f6ee91571b", "practices": [], - "prerequisites": ["numbers", "strings"], + "prerequisites": [ + "numbers", + "strings" + ], "difficulty": 3, "topics": [ - "maps", "core_functions" + "maps", + "core_functions" ] }, { @@ -634,10 +832,13 @@ "name": "Grains", "uuid": "2e57c7d4-d887-4dba-8483-60e026bdf5ea", "practices": [], - "prerequisites": ["numbers"], + "prerequisites": [ + "numbers" + ], "difficulty": 3, "topics": [ - "integers", "recursion" + "integers", + "recursion" ] }, { @@ -645,7 +846,9 @@ "name": "Hexadecimal", "uuid": "a4b1b39a-d942-4921-9b67-2bd913ff52a0", "practices": [], - "prerequisites": ["numbers"], + "prerequisites": [ + "numbers" + ], "difficulty": 3, "topics": [ "math" @@ -656,21 +859,31 @@ "name": "ISBN Verifier", "uuid": "0479e73c-acb3-4a36-949c-a2065bfb57e5", "practices": [], - "prerequisites": ["strings", "booleans"], + "prerequisites": [ + "strings", + "booleans" + ], "difficulty": 3, "topics": [ - "regular_expressions", "conditionals" + "regular_expressions", + "conditionals" ] }, { "slug": "isogram", "name": "Isogram", "uuid": "ced9928a-05dc-4afa-9645-a2f2e548fe6e", - "practices": ["strings"], - "prerequisites": ["strings", "booleans"], + "practices": [ + "strings" + ], + "prerequisites": [ + "strings", + "booleans" + ], "difficulty": 3, "topics": [ - "filtering", "strings" + "filtering", + "strings" ] }, { @@ -678,10 +891,13 @@ "name": "Kindergarten Garden", "uuid": "e40c52a7-9509-4a4d-9ad6-8ca7a3bdca1d", "practices": [], - "prerequisites": ["strings"], + "prerequisites": [ + "strings" + ], "difficulty": 3, "topics": [ - "strings", "conditionals" + "strings", + "conditionals" ] }, { @@ -689,10 +905,14 @@ "name": "Leap", "uuid": "336aa5ec-f868-4a8a-9fd2-989b6c2fd0be", "practices": [], - "prerequisites": ["conditionals", "numbers"], + "prerequisites": [ + "conditionals", + "numbers" + ], "difficulty": 3, "topics": [ - "integers", "conditionals" + "integers", + "conditionals" ] }, { @@ -700,7 +920,9 @@ "name": "Pascal's Triangle", "uuid": "29b16274-b413-4231-a1c7-aff8f93c9b7e", "practices": [], - "prerequisites": ["numbers"], + "prerequisites": [ + "numbers" + ], "difficulty": 3, "topics": [ "math" @@ -711,7 +933,9 @@ "name": "Perfect Numbers", "uuid": "e10b7063-75ac-46d6-848c-c50db87bddc7", "practices": [], - "prerequisites": ["numbers"], + "prerequisites": [ + "numbers" + ], "difficulty": 3, "topics": [ "math" @@ -722,7 +946,9 @@ "name": "Phone Number", "uuid": "41b95380-2bba-407b-b400-7d8a627f18fa", "practices": [], - "prerequisites": ["strings"], + "prerequisites": [ + "strings" + ], "difficulty": 3, "topics": [ "parsing" @@ -733,7 +959,9 @@ "name": "Prime Factors", "uuid": "96005f0f-5153-4915-9f28-326b41b63fab", "practices": [], - "prerequisites": ["numbers"], + "prerequisites": [ + "numbers" + ], "difficulty": 3, "topics": [ "math" @@ -744,21 +972,36 @@ "name": "Proverb", "uuid": "540d93a9-707f-4043-b46c-1dc83f2d50d8", "practices": [], - "prerequisites": ["strings", "vectors"], + "prerequisites": [ + "strings", + "vectors" + ], "difficulty": 3, "topics": [ - "vectors", "strings", "conditionals" + "vectors", + "strings", + "conditionals" ] }, { "slug": "say", "name": "Say", "uuid": "0ff7efbe-855e-4a81-9b64-f07d1557813f", - "practices": ["numbers", "strings", "conditionals"], - "prerequisites": ["numbers", "strings", "conditionals"], + "practices": [ + "numbers", + "strings", + "conditionals" + ], + "prerequisites": [ + "numbers", + "strings", + "conditionals" + ], "difficulty": 3, "topics": [ - "strings", "integers", "exception_handling" + "strings", + "integers", + "exception_handling" ] }, { @@ -766,7 +1009,10 @@ "name": "Trinary", "uuid": "f8a7f5eb-e317-4ffa-bdef-6e30a36511eb", "practices": [], - "prerequisites": ["numbers", "strings"], + "prerequisites": [ + "numbers", + "strings" + ], "difficulty": 3, "topics": [ "math" @@ -777,7 +1023,10 @@ "name": "Allergies", "uuid": "a71bc471-8359-4019-8ad1-e456774388b7", "practices": [], - "prerequisites": ["vectors", "booleans"], + "prerequisites": [ + "vectors", + "booleans" + ], "difficulty": 4, "topics": [ "conditionals" @@ -788,18 +1037,26 @@ "name": "Crypto Square", "uuid": "7387b271-d765-497c-9b85-481c947439b6", "practices": [], - "prerequisites": ["strings"], + "prerequisites": [ + "strings" + ], "difficulty": 4, "topics": [ - "algorithms", "sorting", "regular_expressions" + "algorithms", + "sorting", + "regular_expressions" ] }, { "slug": "difference-of-squares", "name": "Difference of Squares", "uuid": "6f69d8fe-9da2-48f9-a635-b9f54b626daf", - "practices": ["numbers"], - "prerequisites": ["numbers"], + "practices": [ + "numbers" + ], + "prerequisites": [ + "numbers" + ], "difficulty": 4, "topics": [ "math" @@ -810,18 +1067,27 @@ "name": "Dominoes", "uuid": "da04dfa4-5a66-49a5-a7ca-6320cfa4158f", "practices": [], - "prerequisites": ["numbers", "booleans"], + "prerequisites": [ + "numbers", + "booleans" + ], "difficulty": 4, "topics": [ - "graph_theory", "games" + "graph_theory", + "games" ] }, { "slug": "largest-series-product", "name": "Largest Series Product", "uuid": "2978747b-86e6-48f0-aef2-2d00714c8c5e", - "practices": ["numbers"], - "prerequisites": ["numbers", "strings"], + "practices": [ + "numbers" + ], + "prerequisites": [ + "numbers", + "strings" + ], "difficulty": 4, "topics": [ "math" @@ -832,18 +1098,25 @@ "name": "Meetup", "uuid": "81e37fc7-13cd-46a9-987c-c9bda4ff1ead", "practices": [], - "prerequisites": ["numbers"], + "prerequisites": [ + "numbers" + ], "difficulty": 4, "topics": [ - "dates", "time" + "dates", + "time" ] }, { "slug": "octal", "name": "Octal", "uuid": "fa596153-0cbe-40e9-a4d6-1a66fe6ef7e5", - "practices": ["numbers"], - "prerequisites": ["numbers"], + "practices": [ + "numbers" + ], + "prerequisites": [ + "numbers" + ], "difficulty": 4, "topics": [ "math" @@ -854,7 +1127,11 @@ "name": "Spiral Matrix", "uuid": "71d92de0-9f54-4e07-9a8f-fcd477f00219", "practices": [], - "prerequisites": ["vectors", "numbers", "conditionals"], + "prerequisites": [ + "vectors", + "numbers", + "conditionals" + ], "difficulty": 4, "topics": [ "recursivity" @@ -865,10 +1142,13 @@ "name": "Clock", "uuid": "83b7ffc2-aadd-4c26-9794-5e7f851eea8b", "practices": [], - "prerequisites": ["numbers"], + "prerequisites": [ + "numbers" + ], "difficulty": 5, "topics": [ - "dates", "time" + "dates", + "time" ] }, { @@ -876,7 +1156,9 @@ "name": "Diamond", "uuid": "cc0d15ad-d562-458c-8d05-4b213693cfb9", "practices": [], - "prerequisites": ["strings"], + "prerequisites": [ + "strings" + ], "difficulty": 5, "topics": [ "transforming" @@ -887,10 +1169,14 @@ "name": "Luhn", "uuid": "e2d0287c-2fe9-4f46-abfb-4db855d7489b", "practices": [], - "prerequisites": ["numbers", "strings"], + "prerequisites": [ + "numbers", + "strings" + ], "difficulty": 5, "topics": [ - "integers", "conditionals" + "integers", + "conditionals" ] }, { @@ -898,7 +1184,10 @@ "name": "Sieve", "uuid": "0e87bb30-3e7e-49dc-9f80-2d291dfb0111", "practices": [], - "prerequisites": ["vectors", "numbers"], + "prerequisites": [ + "vectors", + "numbers" + ], "difficulty": 5, "topics": [ "math" @@ -908,22 +1197,36 @@ "slug": "robot-simulator", "name": "Robot Simulator", "uuid": "e69ecf2e-8629-4d20-a90f-6de7536247ce", - "practices": ["conditionals"], - "prerequisites": ["conditionals"], + "practices": [ + "conditionals" + ], + "prerequisites": [ + "conditionals" + ], "difficulty": 6, "topics": [ - "strings", "conditionals" + "strings", + "conditionals" ] }, { "slug": "wordy", "name": "Wordy", "uuid": "5528f567-2b5b-498a-b166-984b2c90f6a5", - "practices": ["numbers", "strings", "conditionals"], - "prerequisites": ["numbers", "strings", "conditionals"], + "practices": [ + "numbers", + "strings", + "conditionals" + ], + "prerequisites": [ + "numbers", + "strings", + "conditionals" + ], "difficulty": 6, "topics": [ - "regular_expressions", "parsing" + "regular_expressions", + "parsing" ] }, { @@ -931,7 +1234,10 @@ "name": "Bank Account", "uuid": "d67a7a46-050c-4472-84bd-2e216079a452", "practices": [], - "prerequisites": ["conditionals", "numbers"], + "prerequisites": [ + "conditionals", + "numbers" + ], "difficulty": 7, "topics": [ "conditionals" @@ -942,7 +1248,10 @@ "name": "Matching Brackets", "uuid": "86f005c6-1754-4907-becb-a0997fd52d05", "practices": [], - "prerequisites": ["strings", "booleans"], + "prerequisites": [ + "strings", + "booleans" + ], "difficulty": 7, "topics": [ "parsing" @@ -953,10 +1262,15 @@ "name": "Minesweeper", "uuid": "e07e545c-997f-424b-b4ca-34fd7cc06bf7", "practices": [], - "prerequisites": ["vectors", "conditionals", "strings"], + "prerequisites": [ + "vectors", + "conditionals", + "strings" + ], "difficulty": 7, "topics": [ - "algorithms", "games" + "algorithms", + "games" ] }, { @@ -964,7 +1278,10 @@ "name": "Poker", "uuid": "f842d531-e2a1-4573-90c3-b77177df4787", "practices": [], - "prerequisites": ["conditionals", "strings"], + "prerequisites": [ + "conditionals", + "strings" + ], "difficulty": 7, "topics": [ "games" @@ -975,10 +1292,15 @@ "name": "Queen Attack", "uuid": "edd7932d-50a6-4350-b945-2bb8a8c891c7", "practices": [], - "prerequisites": ["booleans", "conditionals", "numbers"], + "prerequisites": [ + "booleans", + "conditionals", + "numbers" + ], "difficulty": 7, "topics": [ - "equality", "conditionals" + "equality", + "conditionals" ] }, { @@ -986,7 +1308,9 @@ "name": "Go Counting", "uuid": "f0210181-7fe5-49f9-9036-be4256612b3e", "practices": [], - "prerequisites": ["strings"], + "prerequisites": [ + "strings" + ], "difficulty": 9, "topics": [ "games" @@ -997,7 +1321,10 @@ "name": "POV", "uuid": "ca557f64-9e2d-4ab0-8788-4133764ef703", "practices": [], - "prerequisites": ["strings", "vectors"], + "prerequisites": [ + "strings", + "vectors" + ], "difficulty": 10, "topics": [ "conditionals" @@ -1008,7 +1335,10 @@ "name": "Yacht", "uuid": "459c8468-efc4-46a6-bbc0-9937167827a7", "practices": [], - "prerequisites": ["strings", "vectors"], + "prerequisites": [ + "strings", + "vectors" + ], "difficulty": 5, "topics": [ "conditionals" @@ -1019,11 +1349,22 @@ "name": "Zipper", "uuid": "331b2960-baae-4331-a462-a434fd6e8767", "practices": [], - "prerequisites": ["strings", "vectors"], + "prerequisites": [ + "strings", + "vectors" + ], "difficulty": 9, "topics": [ "conditionals" ] + }, + { + "slug": "list-ops", + "name": "List Ops", + "uuid": "699fb4ec-210d-454d-a41a-f7014abf8423", + "practices": [], + "prerequisites": [], + "difficulty": 3 } ] }, @@ -1127,14 +1468,14 @@ } ], "tags": [ + "execution_mode/compiled", "paradigm/declarative", "paradigm/functional", - "typing/dynamic", - "execution_mode/compiled", - "platform/windows", - "platform/mac", "platform/linux", + "platform/mac", + "platform/windows", "runtime/jvm", + "typing/dynamic", "used_for/artificial_intelligence", "used_for/backends", "used_for/cross_platform_development", diff --git a/exercises/practice/list-ops/.docs/instructions.md b/exercises/practice/list-ops/.docs/instructions.md new file mode 100644 index 000000000..ebc5dffed --- /dev/null +++ b/exercises/practice/list-ops/.docs/instructions.md @@ -0,0 +1,19 @@ +# Instructions + +Implement basic list operations. + +In functional languages list operations like `length`, `map`, and `reduce` are very common. +Implement a series of basic list operations, without using existing functions. + +The precise number and names of the operations to be implemented will be track dependent to avoid conflicts with existing names, but the general operations you will implement include: + +- `append` (_given two lists, add all items in the second list to the end of the first list_); +- `concatenate` (_given a series of lists, combine all items in all lists into one flattened list_); +- `filter` (_given a predicate and a list, return the list of all items for which `predicate(item)` is True_); +- `length` (_given a list, return the total number of items within it_); +- `map` (_given a function and a list, return the list of the results of applying `function(item)` on all items_); +- `foldl` (_given a function, a list, and initial accumulator, fold (reduce) each item into the accumulator from the left_); +- `foldr` (_given a function, a list, and an initial accumulator, fold (reduce) each item into the accumulator from the right_); +- `reverse` (_given a list, return a list with all the original items, but in reversed order_). + +Note, the ordering in which arguments are passed to the fold functions (`foldl`, `foldr`) is significant. diff --git a/exercises/practice/list-ops/.meta/config.json b/exercises/practice/list-ops/.meta/config.json new file mode 100644 index 000000000..6d7f4a267 --- /dev/null +++ b/exercises/practice/list-ops/.meta/config.json @@ -0,0 +1,20 @@ +{ + "authors": [ + "bobbicodes" + ], + "contributors": [ + "kahgoh" + ], + "files": { + "solution": [ + "src/list_ops.clj" + ], + "test": [ + "test/list_ops_test.clj" + ], + "example": [ + "src/example.clj" + ] + }, + "blurb": "Implement basic list operations." +} diff --git a/exercises/practice/list-ops/.meta/src/example.clj b/exercises/practice/list-ops/.meta/src/example.clj new file mode 100644 index 000000000..0232d76d0 --- /dev/null +++ b/exercises/practice/list-ops/.meta/src/example.clj @@ -0,0 +1,33 @@ +(ns list-ops) + +(defn append [list1 list2] + (list-ops/foldl (fn [acc elem] (conj acc elem)) list2 list1)) + +(defn concat [list] + (cond + (empty? list) [] + :else (list-ops/foldl (fn [acc elem] (list-ops/append acc elem)) (rest list) (first list)))) + +(defn filter [f list] + (loop [acc [] l list] + (cond + (empty? l) acc + (f (first l)) (recur (conj acc (first l)) (rest l)) + :else (recur acc (rest l))))) + +(defn length [list] + (list-ops/foldl (fn [acc elem] (+ acc 1)) list 0)) + +(defn map [f list] + (list-ops/foldl (fn [acc elem] (conj acc (f elem))) list [])) +(defn foldl [f list init] + (loop [acc init l list] + (cond + (empty? l) acc + :else (recur (f acc (first l)) (rest l))))) + +(defn foldr [f list init] + (list-ops/foldl f (list-ops/reverse list) init)) + +(defn reverse [list] + (list-ops/foldl (fn [acc elem] (cons elem acc)) list [])) \ No newline at end of file diff --git a/exercises/practice/list-ops/.meta/tests.toml b/exercises/practice/list-ops/.meta/tests.toml new file mode 100644 index 000000000..08b1edc04 --- /dev/null +++ b/exercises/practice/list-ops/.meta/tests.toml @@ -0,0 +1,106 @@ +# 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. + +[485b9452-bf94-40f7-a3db-c3cf4850066a] +description = "append entries to a list and return the new list -> empty lists" + +[2c894696-b609-4569-b149-8672134d340a] +description = "append entries to a list and return the new list -> list to empty list" + +[e842efed-3bf6-4295-b371-4d67a4fdf19c] +description = "append entries to a list and return the new list -> empty list to list" + +[71dcf5eb-73ae-4a0e-b744-a52ee387922f] +description = "append entries to a list and return the new list -> non-empty lists" + +[28444355-201b-4af2-a2f6-5550227bde21] +description = "concatenate a list of lists -> empty list" + +[331451c1-9573-42a1-9869-2d06e3b389a9] +description = "concatenate a list of lists -> list of lists" + +[d6ecd72c-197f-40c3-89a4-aa1f45827e09] +description = "concatenate a list of lists -> list of nested lists" + +[0524fba8-3e0f-4531-ad2b-f7a43da86a16] +description = "filter list returning only values that satisfy the filter function -> empty list" + +[88494bd5-f520-4edb-8631-88e415b62d24] +description = "filter list returning only values that satisfy the filter function -> non-empty list" + +[1cf0b92d-8d96-41d5-9c21-7b3c37cb6aad] +description = "returns the length of a list -> empty list" + +[d7b8d2d9-2d16-44c4-9a19-6e5f237cb71e] +description = "returns the length of a list -> non-empty list" + +[c0bc8962-30e2-4bec-9ae4-668b8ecd75aa] +description = "return a list of elements whose values equal the list value transformed by the mapping function -> empty list" + +[11e71a95-e78b-4909-b8e4-60cdcaec0e91] +description = "return a list of elements whose values equal the list value transformed by the mapping function -> non-empty list" + +[613b20b7-1873-4070-a3a6-70ae5f50d7cc] +description = "folds (reduces) the given list from the left with a function -> empty list" +include = false + +[e56df3eb-9405-416a-b13a-aabb4c3b5194] +description = "folds (reduces) the given list from the left with a function -> direction independent function applied to non-empty list" +include = false + +[d2cf5644-aee1-4dfc-9b88-06896676fe27] +description = "folds (reduces) the given list from the left with a function -> direction dependent function applied to non-empty list" +include = false + +[36549237-f765-4a4c-bfd9-5d3a8f7b07d2] +description = "folds (reduces) the given list from the left with a function -> empty list" +reimplements = "613b20b7-1873-4070-a3a6-70ae5f50d7cc" + +[7a626a3c-03ec-42bc-9840-53f280e13067] +description = "folds (reduces) the given list from the left with a function -> direction independent function applied to non-empty list" +reimplements = "e56df3eb-9405-416a-b13a-aabb4c3b5194" + +[d7fcad99-e88e-40e1-a539-4c519681f390] +description = "folds (reduces) the given list from the left with a function -> direction dependent function applied to non-empty list" +reimplements = "d2cf5644-aee1-4dfc-9b88-06896676fe27" + +[aeb576b9-118e-4a57-a451-db49fac20fdc] +description = "folds (reduces) the given list from the right with a function -> empty list" +include = false + +[c4b64e58-313e-4c47-9c68-7764964efb8e] +description = "folds (reduces) the given list from the right with a function -> direction independent function applied to non-empty list" +include = false + +[be396a53-c074-4db3-8dd6-f7ed003cce7c] +description = "folds (reduces) the given list from the right with a function -> direction dependent function applied to non-empty list" +include = false + +[17214edb-20ba-42fc-bda8-000a5ab525b0] +description = "folds (reduces) the given list from the right with a function -> empty list" +reimplements = "aeb576b9-118e-4a57-a451-db49fac20fdc" + +[e1c64db7-9253-4a3d-a7c4-5273b9e2a1bd] +description = "folds (reduces) the given list from the right with a function -> direction independent function applied to non-empty list" +reimplements = "c4b64e58-313e-4c47-9c68-7764964efb8e" + +[8066003b-f2ff-437e-9103-66e6df474844] +description = "folds (reduces) the given list from the right with a function -> direction dependent function applied to non-empty list" +reimplements = "be396a53-c074-4db3-8dd6-f7ed003cce7c" + +[94231515-050e-4841-943d-d4488ab4ee30] +description = "reverse the elements of the list -> empty list" + +[fcc03d1e-42e0-4712-b689-d54ad761f360] +description = "reverse the elements of the list -> non-empty list" + +[40872990-b5b8-4cb8-9085-d91fc0d05d26] +description = "reverse the elements of the list -> list of lists is not flattened" diff --git a/exercises/practice/list-ops/deps.edn b/exercises/practice/list-ops/deps.edn new file mode 100644 index 000000000..561c3e2da --- /dev/null +++ b/exercises/practice/list-ops/deps.edn @@ -0,0 +1,6 @@ +{:aliases {:test {:extra-paths ["test"] + :extra-deps {io.github.cognitect-labs/test-runner + {:git/url "https://github.com/cognitect-labs/test-runner.git" + :sha "705ad25bbf0228b1c38d0244a36001c2987d7337"}} + :main-opts ["-m" "cognitect.test-runner"] + :exec-fn cognitect.test-runner.api/test}}} \ No newline at end of file diff --git a/exercises/practice/list-ops/project.clj b/exercises/practice/list-ops/project.clj new file mode 100644 index 000000000..31eb1b1b7 --- /dev/null +++ b/exercises/practice/list-ops/project.clj @@ -0,0 +1,4 @@ +(defproject list-ops "0.1.0-SNAPSHOT" + :description "list-ops exercise." + :url "https://github.com/exercism/clojure/tree/main/exercises/list-ops" + :dependencies [[org.clojure/clojure "1.10.0"]]) diff --git a/exercises/practice/list-ops/src/list_ops.clj b/exercises/practice/list-ops/src/list_ops.clj new file mode 100644 index 000000000..4c4a4b7e3 --- /dev/null +++ b/exercises/practice/list-ops/src/list_ops.clj @@ -0,0 +1,33 @@ +(ns list-ops) + +(defn append [list1 list2] ;; <- arglist goes here + ;; your code goes here +) + +(defn concat [list] ;; <- arglist goes here + ;; your code goes here +) + +(defn filter [f list] ;; <- arglist goes here + ;; your code goes here +) + +(defn length [list] ;; <- arglist goes here + ;; your code goes here +) + +(defn map [f list] ;; <- arglist goes here + ;; your code goes here +) + +(defn foldl [f list init] ;; <- arglist goes here + ;; your code goes here +) + +(defn foldr [f list init] ;; <- arglist goes here + ;; your code goes here +) + +(defn reverse [list] ;; <- arglist goes here + ;; your code goes here +) \ No newline at end of file diff --git a/exercises/practice/list-ops/test/list_ops_test.clj b/exercises/practice/list-ops/test/list_ops_test.clj new file mode 100644 index 000000000..c144dcf4c --- /dev/null +++ b/exercises/practice/list-ops/test/list_ops_test.clj @@ -0,0 +1,65 @@ +(ns list-ops-test + (:require [clojure.test :refer [deftest testing is]] + list-ops)) + +(deftest append-test + (testing "empty lists" + (is (= [] (list-ops/append [] [])))) + (testing "list to empty list" + (is (= [1 2 3 4] (list-ops/append [] [1 2 3 4])))) + (testing "empty list to list" + (is (= [1 2 3 4] (list-ops/append [1 2 3 4] [])))) + (testing "non-empty lists" + (is (= [1 2 2 3 4 5] (list-ops/append [1 2] [2 3 4 5]))))) + +(deftest concat-test + (testing "empty list" + (is (= [] (list-ops/concat [])))) + (testing "list of lists" + (is (= [1 2 3 4 5 6] (list-ops/concat [[1 2] [3] [] [4 5 6]])))) + (testing "list of nested lists" + (is (= [[1] [2] [3] [] [4 5 6]] (list-ops/concat [[[1] [2]] [[3]] [[]] [[4 5 6]]]))))) + +(deftest filter-test + (testing "empty list" + (is (= [] (list-ops/filter (fn [x] (= (mod x 2) 1)) []))) + (testing "non-empty list" + (is (= [1 3 5] (list-ops/filter (fn [x] (= (mod x 2) 1)) [1 2 3 5])))))) + +(deftest length-test + (testing "empty list" + (is (= 0 (list-ops/length [])))) + (testing "non-empty list" + (is (= 4 (list-ops/length [1 2 3 4]))))) + +(deftest map-test + (testing "empty list" + (is (= [] (list-ops/map (fn [x] (+ x 1)) [])))) + (testing "non-empty list" + (is (= [2 4 6 8] (list-ops/map (fn [x] (+ x 1)) [1 3 5 7]))))) + +(deftest foldl-test + (testing "empty list" + (is (= 2 (list-ops/foldl (fn [acc el] (* el acc)) [] 2)))) + (testing "direction independent function applied to non-empty list" + (is (= 15 (list-ops/foldl (fn [acc el] (+ el acc)) [1 2 3 4] 5)))) + (testing "direction dependent function applied to non-empty list" + (is (= 64 (list-ops/foldl (fn [acc el] (/ el acc)) [1 2 3 4] 24))))) + +(deftest foldr-test + (testing "empty list" + (is (= 2 (list-ops/foldr (fn [acc el] (* el acc)) [] 2)))) + (testing "direction independent function applied to non-empty list" + (is (= 15 (list-ops/foldr (fn [acc el] (+ el acc)) [1 2 3 4] 5)))) + (testing "direction dependent function applied to non-empty list" + (is (= 9 (list-ops/foldr (fn [acc el] (/ el acc)) [1 2 3 4] 24))))) + +(deftest reverse-test + (testing "empty list" + (is (= [] (list-ops/reverse [])))) + (testing "non-empty list" + (is (= [7 5 3 1] (list-ops/reverse [1 3 5 7])))) + (testing "list of lists is not flattened" + (is (= [[4 5 6] [] [3] [1 2]] (list-ops/reverse [[1 2] [3] [] [4 5 6]]))))) + +;(clojure.test/run-tests) \ No newline at end of file diff --git a/generator.clj b/generator.clj deleted file mode 100644 index 3c97c757b..000000000 --- a/generator.clj +++ /dev/null @@ -1,140 +0,0 @@ -#!/usr/bin/env bb - -(require '[cheshire.core :as json] - '[babashka.fs :as fs] - '[clojure.string :as str]) - -(comment - (def slug "zipper")) - -(def data - (let [url "https://raw.githubusercontent.com/exercism/problem-specifications/main/exercises/"] - {:canonical-data (json/parse-string (slurp (str url "/" slug "/canonical-data.json")) true) - :description (slurp (str url "/" slug "/description.md")) - :metadata (slurp (str url "/" slug "/metadata.toml"))})) - -(second - (str/split (:metadata data) #"=")) - -(defn get-meta - "Returns a vector containing the exercise title and blurb" - [data] - (mapv last - (map #(map str/trim (str/split % #"=")) - (str/split-lines (:metadata data))))) - -(defn init-deps [data] - (fs/create-dirs (fs/path "exercises" "practice" - (:exercise (:canonical-data data)) "src")) - (spit (str (fs/file "exercises" "practice" - (:exercise (:canonical-data data)) - "deps.edn")) - "{:aliases {:test {:extra-paths [\"test\"] - :extra-deps {io.github.cognitect-labs/test-runner - {:git/url \"https://github.com/cognitect-labs/test-runner.git\" - :sha \"705ad25bbf0228b1c38d0244a36001c2987d7337\"}} - :main-opts [\"-m\" \"cognitect.test-runner\"] - :exec-fn cognitect.test-runner.api/test}}}")) - -(defn init-lein [data] - (let [slug (:exercise (:canonical-data data))] - (spit (str (fs/file "exercises" "practice" - (:exercise (:canonical-data data)) "project.clj")) - (str "(defproject " slug " \"0.1.0-SNAPSHOT\" - :description \"" slug " exercise.\" - :url \"https://github.com/exercism/clojure/tree/master/exercises/" slug "\" - :dependencies [[org.clojure/clojure \"1.10.0\"]]) -")))) - -(defn test-ns-form [data] - (str "(ns " (:exercise data) "-test - (:require [clojure.test :refer [deftest testing is]]\n " - (:exercise data) "))\n\n")) - -(defn src-ns-form [data] - (str "(ns " (:exercise data) ")\n\n")) - -(defn testing-form [slug test-case] - (let [property (symbol (str slug "/" (:property test-case))) - input (:input test-case) - args (map #(get input %) (keys input))] - (str " (testing \"" (:description test-case) "\" - (is (= " (:expected test-case) " " - (reverse (into (list property) args)) ")))"))) - -(defn zipper-generator [slug test-case] - (let [input (:input test-case) - ops (for [op (:operations input)] - (if (contains? op :item) - (str "(zipper/" (:operation op) " " - (if (nil? (:item op)) - "nil" - (str (:item op))) ")") - (str "zipper/" (:operation op))))] - (str " (testing \"" (:description test-case) "\" - (is (= " (if (nil? (:value (:expected test-case))) - "nil" (:value (:expected test-case))) " " - "\n (-> " (:initialTree input) "\n " - (apply str (interpose "\n " ops)) "))))"))) - -(defn testing-forms - "Outputs a sequence of the test cases for a given property name - given its name as a string and the canonical data." - [property data] - (let [test-cases (filter #(= property (:property %)) (:cases data))] - (map #(zipper-generator (:exercise data) %) test-cases))) - -(defn deftest-forms [data] - (for [property (distinct (map :property (:cases (:canonical-data data))))] - (str "(deftest " property "-test\n" - (apply str (interpose "\n" - (testing-forms property (:canonical-data data)))) - ")"))) - -(defn init-tests [data] - #_(fs/create-dir (fs/path "exercises" "practice" - (:exercise (:canonical-data data)) "test")) - (spit (str (fs/file "exercises" "practice" - (:exercise (:canonical-data data)) "test" - (str (str/replace (:exercise (:canonical-data data)) "-" "_") - "_test.clj"))) - (str (test-ns-form (:canonical-data data)) - (apply str (interpose "\n\n" - (deftest-forms data)))))) - -(defn init-src [data] - (spit (str (fs/file "exercises" "practice" (:exercise (:canonical-data data)) "src" - (str (str/replace (:exercise (:canonical-data data)) - "-" "_") ".clj"))) - (str (src-ns-form (:canonical-data data)) - (apply str (interpose "\n\n" - (for [property (distinct (map :property (:cases (:canonical-data data))))] - (str "(defn " property " []\n )"))))))) - -(defn init-description! [data] - (let [path ["exercises" "practice" (:exercise (:canonical-data data)) ".docs"]] - (when-not (fs/directory? (apply fs/path path)) - (fs/create-dir (apply fs/path path)) - (spit (str (apply fs/file (conj path "instructions.md"))) - (:description data))))) - -(defn config [data author blurb] - (let [slug (:exercise (:canonical-data data))] - {:authors [author], - :contributors [], - :files {:solution [(str "src/" (str/replace slug "-" "_") ".clj")], - :test [(str "test/" (str/replace slug "-" "_") "_test.clj")], - :example [".meta/src/example.clj"]}, - :blurb blurb})) - -(defn init-config! [data] - (let [path ["exercises" "practice" (:exercise (:canonical-data data)) ".meta"]] - (when-not (fs/directory? (apply fs/path path)) - (fs/create-dirs (apply fs/path (conj path "src"))) - (spit (str (apply fs/file (conj path "config.json"))) - (json/generate-string (config data "porkostomus" (last (get-meta data))) - {:pretty true}))))) - -(comment - (init-config! data) - ) \ No newline at end of file From 05097533099061ad8b1b4dd1058b3cd847b0ea99 Mon Sep 17 00:00:00 2001 From: Kah Goh Date: Sun, 22 Sep 2024 21:11:46 +0800 Subject: [PATCH 02/12] Fix link to example --- exercises/practice/list-ops/.meta/config.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/exercises/practice/list-ops/.meta/config.json b/exercises/practice/list-ops/.meta/config.json index 6d7f4a267..98fbffdf3 100644 --- a/exercises/practice/list-ops/.meta/config.json +++ b/exercises/practice/list-ops/.meta/config.json @@ -13,7 +13,7 @@ "test/list_ops_test.clj" ], "example": [ - "src/example.clj" + ".meta/src/example.clj" ] }, "blurb": "Implement basic list operations." From 9930f51d5eb928d9439ee8afcd2607c67af9642c Mon Sep 17 00:00:00 2001 From: Kah Goh Date: Sun, 22 Sep 2024 21:28:37 +0800 Subject: [PATCH 03/12] Add prerequisites & trim whitespace --- config.json | 5 ++++- exercises/practice/list-ops/.meta/src/example.clj | 4 ++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/config.json b/config.json index 9bbb00990..ad6d0a3c4 100644 --- a/config.json +++ b/config.json @@ -1363,7 +1363,10 @@ "name": "List Ops", "uuid": "699fb4ec-210d-454d-a41a-f7014abf8423", "practices": [], - "prerequisites": [], + "prerequisites": [ + "lists", + "closures" + ], "difficulty": 3 } ] diff --git a/exercises/practice/list-ops/.meta/src/example.clj b/exercises/practice/list-ops/.meta/src/example.clj index 0232d76d0..b8f738ecb 100644 --- a/exercises/practice/list-ops/.meta/src/example.clj +++ b/exercises/practice/list-ops/.meta/src/example.clj @@ -1,6 +1,6 @@ (ns list-ops) -(defn append [list1 list2] +(defn append [list1 list2] (list-ops/foldl (fn [acc elem] (conj acc elem)) list2 list1)) (defn concat [list] @@ -10,7 +10,7 @@ (defn filter [f list] (loop [acc [] l list] - (cond + (cond (empty? l) acc (f (first l)) (recur (conj acc (first l)) (rest l)) :else (recur acc (rest l))))) From 8ca6bc00cbb1a48534c002c7ef5272740e33ad01 Mon Sep 17 00:00:00 2001 From: Kah Goh Date: Sun, 22 Sep 2024 21:47:30 +0800 Subject: [PATCH 04/12] Fix list-ops test --- .../practice/list-ops/.meta/src/example.clj | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/exercises/practice/list-ops/.meta/src/example.clj b/exercises/practice/list-ops/.meta/src/example.clj index b8f738ecb..f6e24e3d5 100644 --- a/exercises/practice/list-ops/.meta/src/example.clj +++ b/exercises/practice/list-ops/.meta/src/example.clj @@ -1,5 +1,11 @@ (ns list-ops) +(defn foldl [f list init] + (loop [acc init l list] + (cond + (empty? l) acc + :else (recur (f acc (first l)) (rest l))))) + (defn append [list1 list2] (list-ops/foldl (fn [acc elem] (conj acc elem)) list2 list1)) @@ -20,14 +26,9 @@ (defn map [f list] (list-ops/foldl (fn [acc elem] (conj acc (f elem))) list [])) -(defn foldl [f list init] - (loop [acc init l list] - (cond - (empty? l) acc - :else (recur (f acc (first l)) (rest l))))) + +(defn reverse [list] + (list-ops/foldl (fn [acc elem] (cons elem acc)) list [])) (defn foldr [f list init] (list-ops/foldl f (list-ops/reverse list) init)) - -(defn reverse [list] - (list-ops/foldl (fn [acc elem] (cons elem acc)) list [])) \ No newline at end of file From 38149940871664b26495091c73e93dc9ad23c45f Mon Sep 17 00:00:00 2001 From: Kah Goh Date: Mon, 23 Sep 2024 19:34:14 +0800 Subject: [PATCH 05/12] Add back generator.clj and remove unneeded comments from list_ops.clj --- exercises/practice/list-ops/src/list_ops.clj | 18 +-- generator.clj | 140 +++++++++++++++++++ 2 files changed, 149 insertions(+), 9 deletions(-) create mode 100644 generator.clj diff --git a/exercises/practice/list-ops/src/list_ops.clj b/exercises/practice/list-ops/src/list_ops.clj index 4c4a4b7e3..e200e5650 100644 --- a/exercises/practice/list-ops/src/list_ops.clj +++ b/exercises/practice/list-ops/src/list_ops.clj @@ -1,33 +1,33 @@ (ns list-ops) -(defn append [list1 list2] ;; <- arglist goes here +(defn append [list1 list2] ;; your code goes here ) -(defn concat [list] ;; <- arglist goes here +(defn concat [list] ;; your code goes here ) -(defn filter [f list] ;; <- arglist goes here +(defn filter [f list] ;; your code goes here ) -(defn length [list] ;; <- arglist goes here +(defn length [list] ;; your code goes here ) -(defn map [f list] ;; <- arglist goes here +(defn map [f list] ;; your code goes here ) -(defn foldl [f list init] ;; <- arglist goes here +(defn foldl [f list init] ;; your code goes here ) -(defn foldr [f list init] ;; <- arglist goes here +(defn foldr [f list init] ;; your code goes here ) -(defn reverse [list] ;; <- arglist goes here +(defn reverse [list] ;; your code goes here -) \ No newline at end of file +) diff --git a/generator.clj b/generator.clj new file mode 100644 index 000000000..3c97c757b --- /dev/null +++ b/generator.clj @@ -0,0 +1,140 @@ +#!/usr/bin/env bb + +(require '[cheshire.core :as json] + '[babashka.fs :as fs] + '[clojure.string :as str]) + +(comment + (def slug "zipper")) + +(def data + (let [url "https://raw.githubusercontent.com/exercism/problem-specifications/main/exercises/"] + {:canonical-data (json/parse-string (slurp (str url "/" slug "/canonical-data.json")) true) + :description (slurp (str url "/" slug "/description.md")) + :metadata (slurp (str url "/" slug "/metadata.toml"))})) + +(second + (str/split (:metadata data) #"=")) + +(defn get-meta + "Returns a vector containing the exercise title and blurb" + [data] + (mapv last + (map #(map str/trim (str/split % #"=")) + (str/split-lines (:metadata data))))) + +(defn init-deps [data] + (fs/create-dirs (fs/path "exercises" "practice" + (:exercise (:canonical-data data)) "src")) + (spit (str (fs/file "exercises" "practice" + (:exercise (:canonical-data data)) + "deps.edn")) + "{:aliases {:test {:extra-paths [\"test\"] + :extra-deps {io.github.cognitect-labs/test-runner + {:git/url \"https://github.com/cognitect-labs/test-runner.git\" + :sha \"705ad25bbf0228b1c38d0244a36001c2987d7337\"}} + :main-opts [\"-m\" \"cognitect.test-runner\"] + :exec-fn cognitect.test-runner.api/test}}}")) + +(defn init-lein [data] + (let [slug (:exercise (:canonical-data data))] + (spit (str (fs/file "exercises" "practice" + (:exercise (:canonical-data data)) "project.clj")) + (str "(defproject " slug " \"0.1.0-SNAPSHOT\" + :description \"" slug " exercise.\" + :url \"https://github.com/exercism/clojure/tree/master/exercises/" slug "\" + :dependencies [[org.clojure/clojure \"1.10.0\"]]) +")))) + +(defn test-ns-form [data] + (str "(ns " (:exercise data) "-test + (:require [clojure.test :refer [deftest testing is]]\n " + (:exercise data) "))\n\n")) + +(defn src-ns-form [data] + (str "(ns " (:exercise data) ")\n\n")) + +(defn testing-form [slug test-case] + (let [property (symbol (str slug "/" (:property test-case))) + input (:input test-case) + args (map #(get input %) (keys input))] + (str " (testing \"" (:description test-case) "\" + (is (= " (:expected test-case) " " + (reverse (into (list property) args)) ")))"))) + +(defn zipper-generator [slug test-case] + (let [input (:input test-case) + ops (for [op (:operations input)] + (if (contains? op :item) + (str "(zipper/" (:operation op) " " + (if (nil? (:item op)) + "nil" + (str (:item op))) ")") + (str "zipper/" (:operation op))))] + (str " (testing \"" (:description test-case) "\" + (is (= " (if (nil? (:value (:expected test-case))) + "nil" (:value (:expected test-case))) " " + "\n (-> " (:initialTree input) "\n " + (apply str (interpose "\n " ops)) "))))"))) + +(defn testing-forms + "Outputs a sequence of the test cases for a given property name + given its name as a string and the canonical data." + [property data] + (let [test-cases (filter #(= property (:property %)) (:cases data))] + (map #(zipper-generator (:exercise data) %) test-cases))) + +(defn deftest-forms [data] + (for [property (distinct (map :property (:cases (:canonical-data data))))] + (str "(deftest " property "-test\n" + (apply str (interpose "\n" + (testing-forms property (:canonical-data data)))) + ")"))) + +(defn init-tests [data] + #_(fs/create-dir (fs/path "exercises" "practice" + (:exercise (:canonical-data data)) "test")) + (spit (str (fs/file "exercises" "practice" + (:exercise (:canonical-data data)) "test" + (str (str/replace (:exercise (:canonical-data data)) "-" "_") + "_test.clj"))) + (str (test-ns-form (:canonical-data data)) + (apply str (interpose "\n\n" + (deftest-forms data)))))) + +(defn init-src [data] + (spit (str (fs/file "exercises" "practice" (:exercise (:canonical-data data)) "src" + (str (str/replace (:exercise (:canonical-data data)) + "-" "_") ".clj"))) + (str (src-ns-form (:canonical-data data)) + (apply str (interpose "\n\n" + (for [property (distinct (map :property (:cases (:canonical-data data))))] + (str "(defn " property " []\n )"))))))) + +(defn init-description! [data] + (let [path ["exercises" "practice" (:exercise (:canonical-data data)) ".docs"]] + (when-not (fs/directory? (apply fs/path path)) + (fs/create-dir (apply fs/path path)) + (spit (str (apply fs/file (conj path "instructions.md"))) + (:description data))))) + +(defn config [data author blurb] + (let [slug (:exercise (:canonical-data data))] + {:authors [author], + :contributors [], + :files {:solution [(str "src/" (str/replace slug "-" "_") ".clj")], + :test [(str "test/" (str/replace slug "-" "_") "_test.clj")], + :example [".meta/src/example.clj"]}, + :blurb blurb})) + +(defn init-config! [data] + (let [path ["exercises" "practice" (:exercise (:canonical-data data)) ".meta"]] + (when-not (fs/directory? (apply fs/path path)) + (fs/create-dirs (apply fs/path (conj path "src"))) + (spit (str (apply fs/file (conj path "config.json"))) + (json/generate-string (config data "porkostomus" (last (get-meta data))) + {:pretty true}))))) + +(comment + (init-config! data) + ) \ No newline at end of file From 53cd83dede055e30ee70d2d932d4aed810ce6e02 Mon Sep 17 00:00:00 2001 From: Kah Goh Date: Fri, 27 Sep 2024 22:21:26 +0800 Subject: [PATCH 06/12] Rename list functions --- config.json | 3 +- .../practice/list-ops/.meta/src/example.clj | 36 +++++++++---------- exercises/practice/list-ops/src/list_ops.clj | 31 +++++++++++----- .../practice/list-ops/test/list_ops_test.clj | 28 +++++++-------- 4 files changed, 57 insertions(+), 41 deletions(-) diff --git a/config.json b/config.json index ad6d0a3c4..aacb72eb8 100644 --- a/config.json +++ b/config.json @@ -1367,7 +1367,8 @@ "lists", "closures" ], - "difficulty": 3 + "difficulty": 5, + "status": "wip" } ] }, diff --git a/exercises/practice/list-ops/.meta/src/example.clj b/exercises/practice/list-ops/.meta/src/example.clj index f6e24e3d5..c4bc083f6 100644 --- a/exercises/practice/list-ops/.meta/src/example.clj +++ b/exercises/practice/list-ops/.meta/src/example.clj @@ -1,34 +1,34 @@ (ns list-ops) -(defn foldl [f list init] - (loop [acc init l list] +(defn foldl [f coll init] + (loop [acc init l coll] (cond (empty? l) acc :else (recur (f acc (first l)) (rest l))))) -(defn append [list1 list2] - (list-ops/foldl (fn [acc elem] (conj acc elem)) list2 list1)) +(defn append [coll1 coll2] + (list-ops/foldl (fn [acc elem] (conj acc elem)) coll2 coll1)) -(defn concat [list] +(defn concatenate [coll] (cond - (empty? list) [] - :else (list-ops/foldl (fn [acc elem] (list-ops/append acc elem)) (rest list) (first list)))) + (empty? coll) [] + :else (list-ops/foldl (fn [acc elem] (list-ops/append acc elem)) (rest coll) (first coll)))) -(defn filter [f list] - (loop [acc [] l list] +(defn select-if [pred coll] + (loop [acc [] l coll] (cond (empty? l) acc - (f (first l)) (recur (conj acc (first l)) (rest l)) + (pred (first l)) (recur (conj acc (first l)) (rest l)) :else (recur acc (rest l))))) -(defn length [list] - (list-ops/foldl (fn [acc elem] (+ acc 1)) list 0)) +(defn length [coll] + (list-ops/foldl (fn [acc elem] (+ acc 1)) coll 0)) -(defn map [f list] - (list-ops/foldl (fn [acc elem] (conj acc (f elem))) list [])) +(defn apply-to-each [f coll] + (list-ops/foldl (fn [acc elem] (conj acc (f elem))) coll [])) -(defn reverse [list] - (list-ops/foldl (fn [acc elem] (cons elem acc)) list [])) +(defn reverse-order [coll] + (list-ops/foldl (fn [acc elem] (cons elem acc)) coll [])) -(defn foldr [f list init] - (list-ops/foldl f (list-ops/reverse list) init)) +(defn foldr [f coll init] + (list-ops/foldl f (list-ops/reverse-order coll) init)) diff --git a/exercises/practice/list-ops/src/list_ops.clj b/exercises/practice/list-ops/src/list_ops.clj index e200e5650..a4bf288f4 100644 --- a/exercises/practice/list-ops/src/list_ops.clj +++ b/exercises/practice/list-ops/src/list_ops.clj @@ -1,33 +1,48 @@ (ns list-ops) -(defn append [list1 list2] +(defn append + "Given two lists, adds all the items in the second list to the end of the first list" + [coll1 coll2] ;; your code goes here ) -(defn concat [list] +(defn concatenate + "Given a series of lists, combines all the lists into one flattened list" + [coll] ;; your code goes here ) -(defn filter [f list] +(defn select-if + "Given a predicate and a list, returns the list of all items for which `predicate(item)` is True" + [pred coll] ;; your code goes here ) -(defn length [list] +(defn length + "Given a list, returns the number of items within it" + [coll] ;; your code goes here ) -(defn map [f list] +(defn apply-to-each + "Given a function and a list, returns the list of the results of applying `function(item)` on all items" + [f coll] ;; your code goes here ) -(defn foldl [f list init] +(defn foldl + "Given a function, a list, and initial accumulator, folds (reduces) each item into the accumulator from the left" + [f coll init] ;; your code goes here ) -(defn foldr [f list init] +(defn foldr [f coll init] + "Given a function, a list, and an initial accumulator, folds (reduces) each item into the accumulator from the right" ;; your code goes here ) -(defn reverse [list] +(defn reverse-order + "Given a list, returns a list with all the original items, but in reverse order" + [coll] ;; your code goes here ) diff --git a/exercises/practice/list-ops/test/list_ops_test.clj b/exercises/practice/list-ops/test/list_ops_test.clj index c144dcf4c..490bbc5b7 100644 --- a/exercises/practice/list-ops/test/list_ops_test.clj +++ b/exercises/practice/list-ops/test/list_ops_test.clj @@ -12,19 +12,19 @@ (testing "non-empty lists" (is (= [1 2 2 3 4 5] (list-ops/append [1 2] [2 3 4 5]))))) -(deftest concat-test +(deftest concatenate-test (testing "empty list" - (is (= [] (list-ops/concat [])))) + (is (= [] (list-ops/concatenate [])))) (testing "list of lists" - (is (= [1 2 3 4 5 6] (list-ops/concat [[1 2] [3] [] [4 5 6]])))) + (is (= [1 2 3 4 5 6] (list-ops/concatenate [[1 2] [3] [] [4 5 6]])))) (testing "list of nested lists" - (is (= [[1] [2] [3] [] [4 5 6]] (list-ops/concat [[[1] [2]] [[3]] [[]] [[4 5 6]]]))))) + (is (= [[1] [2] [3] [] [4 5 6]] (list-ops/concatenate [[[1] [2]] [[3]] [[]] [[4 5 6]]]))))) -(deftest filter-test +(deftest select-if-test (testing "empty list" - (is (= [] (list-ops/filter (fn [x] (= (mod x 2) 1)) []))) + (is (= [] (list-ops/select-if (fn [x] (= (mod x 2) 1)) []))) (testing "non-empty list" - (is (= [1 3 5] (list-ops/filter (fn [x] (= (mod x 2) 1)) [1 2 3 5])))))) + (is (= [1 3 5] (list-ops/select-if (fn [x] (= (mod x 2) 1)) [1 2 3 5])))))) (deftest length-test (testing "empty list" @@ -32,11 +32,11 @@ (testing "non-empty list" (is (= 4 (list-ops/length [1 2 3 4]))))) -(deftest map-test +(deftest apply-to-each-test (testing "empty list" - (is (= [] (list-ops/map (fn [x] (+ x 1)) [])))) + (is (= [] (list-ops/apply-to-each (fn [x] (+ x 1)) [])))) (testing "non-empty list" - (is (= [2 4 6 8] (list-ops/map (fn [x] (+ x 1)) [1 3 5 7]))))) + (is (= [2 4 6 8] (list-ops/apply-to-each (fn [x] (+ x 1)) [1 3 5 7]))))) (deftest foldl-test (testing "empty list" @@ -54,12 +54,12 @@ (testing "direction dependent function applied to non-empty list" (is (= 9 (list-ops/foldr (fn [acc el] (/ el acc)) [1 2 3 4] 24))))) -(deftest reverse-test +(deftest reverse-order-test (testing "empty list" - (is (= [] (list-ops/reverse [])))) + (is (= [] (list-ops/reverse-order [])))) (testing "non-empty list" - (is (= [7 5 3 1] (list-ops/reverse [1 3 5 7])))) + (is (= [7 5 3 1] (list-ops/reverse-order [1 3 5 7])))) (testing "list of lists is not flattened" - (is (= [[4 5 6] [] [3] [1 2]] (list-ops/reverse [[1 2] [3] [] [4 5 6]]))))) + (is (= [[4 5 6] [] [3] [1 2]] (list-ops/reverse-order [[1 2] [3] [] [4 5 6]]))))) ;(clojure.test/run-tests) \ No newline at end of file From beedaca5b07ad490a8d90bb4c896c572b2059a8a Mon Sep 17 00:00:00 2001 From: Kah Goh Date: Sat, 28 Sep 2024 17:21:39 +0800 Subject: [PATCH 07/12] Change list references to collection Co-authored-by: Anastasios Chatzialexiou <16361161+tasxatzial@users.noreply.github.com> --- exercises/practice/list-ops/src/list_ops.clj | 21 ++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/exercises/practice/list-ops/src/list_ops.clj b/exercises/practice/list-ops/src/list_ops.clj index a4bf288f4..31248d474 100644 --- a/exercises/practice/list-ops/src/list_ops.clj +++ b/exercises/practice/list-ops/src/list_ops.clj @@ -1,48 +1,49 @@ (ns list-ops) (defn append - "Given two lists, adds all the items in the second list to the end of the first list" + "Given two collections, it adds all the items in the second collection to the end of the first collection" [coll1 coll2] ;; your code goes here ) (defn concatenate - "Given a series of lists, combines all the lists into one flattened list" - [coll] + "Given a series of collections, it combines all the collections into one flattened collection" + [colls] ;; your code goes here ) (defn select-if - "Given a predicate and a list, returns the list of all items for which `predicate(item)` is True" + "Given a predicate and a collection, it returns the collection of all items for which predicate(item) is true" [pred coll] ;; your code goes here ) (defn length - "Given a list, returns the number of items within it" + "Given a collection, it returns the number of items within it" [coll] ;; your code goes here ) (defn apply-to-each - "Given a function and a list, returns the list of the results of applying `function(item)` on all items" + "Given a function and a collection, it returns the collection of the results of applying function(item) on all items" [f coll] ;; your code goes here ) (defn foldl - "Given a function, a list, and initial accumulator, folds (reduces) each item into the accumulator from the left" + "Given a function, a collection, and initial accumulator, it folds (reduces) each item into the accumulator from the left" [f coll init] ;; your code goes here ) -(defn foldr [f coll init] - "Given a function, a list, and an initial accumulator, folds (reduces) each item into the accumulator from the right" +(defn foldr + "Given a function, a collection, and an initial accumulator, it folds (reduces) each item into the accumulator from the right" + [f coll init] ;; your code goes here ) (defn reverse-order - "Given a list, returns a list with all the original items, but in reverse order" + "Given a collection, it returns a collection with all the original items, but in reverse order" [coll] ;; your code goes here ) From 7be9dc4f0ffd2ccfbabb8233e407feaa5d0da284 Mon Sep 17 00:00:00 2001 From: Kah Goh Date: Sat, 5 Oct 2024 20:56:06 +0800 Subject: [PATCH 08/12] Change references to vectors --- exercises/practice/list-ops/src/list_ops.clj | 21 +++++---- .../practice/list-ops/test/list_ops_test.clj | 44 +++++++++---------- 2 files changed, 32 insertions(+), 33 deletions(-) diff --git a/exercises/practice/list-ops/src/list_ops.clj b/exercises/practice/list-ops/src/list_ops.clj index 31248d474..6e4ae03cc 100644 --- a/exercises/practice/list-ops/src/list_ops.clj +++ b/exercises/practice/list-ops/src/list_ops.clj @@ -1,49 +1,48 @@ (ns list-ops) (defn append - "Given two collections, it adds all the items in the second collection to the end of the first collection" + "Given two vectors, it adds all the items in the second vector to the end of the first vector" [coll1 coll2] ;; your code goes here ) (defn concatenate - "Given a series of collections, it combines all the collections into one flattened collection" - [colls] + "Given a series of vectors, it combines all the vectors into one flattened vector" + [coll] ;; your code goes here ) (defn select-if - "Given a predicate and a collection, it returns the collection of all items for which predicate(item) is true" + "Given a predicate and a vector, it returns the vector of all items for which `predicate(item)` is True" [pred coll] ;; your code goes here ) (defn length - "Given a collection, it returns the number of items within it" + "Given a vector, it returns the number of items within it" [coll] ;; your code goes here ) (defn apply-to-each - "Given a function and a collection, it returns the collection of the results of applying function(item) on all items" + "Given a function and a vector, it returns the vector of the results of applying `function(item)` on all items" [f coll] ;; your code goes here ) (defn foldl - "Given a function, a collection, and initial accumulator, it folds (reduces) each item into the accumulator from the left" + "Given a function, a vector, and initial accumulator, it folds (reduces) each item into the accumulator from the left" [f coll init] ;; your code goes here ) -(defn foldr - "Given a function, a collection, and an initial accumulator, it folds (reduces) each item into the accumulator from the right" - [f coll init] +(defn foldr [f coll init] + "Given a function, a vector, and an initial accumulator, it folds (reduces) each item into the accumulator from the right" ;; your code goes here ) (defn reverse-order - "Given a collection, it returns a collection with all the original items, but in reverse order" + "Given a vector, it returns a vector with all the original items, but in reverse order" [coll] ;; your code goes here ) diff --git a/exercises/practice/list-ops/test/list_ops_test.clj b/exercises/practice/list-ops/test/list_ops_test.clj index 490bbc5b7..a4598999d 100644 --- a/exercises/practice/list-ops/test/list_ops_test.clj +++ b/exercises/practice/list-ops/test/list_ops_test.clj @@ -3,63 +3,63 @@ list-ops)) (deftest append-test - (testing "empty lists" + (testing "empty vectors" (is (= [] (list-ops/append [] [])))) - (testing "list to empty list" + (testing "vector to empty vector" (is (= [1 2 3 4] (list-ops/append [] [1 2 3 4])))) - (testing "empty list to list" + (testing "empty vector to vector" (is (= [1 2 3 4] (list-ops/append [1 2 3 4] [])))) - (testing "non-empty lists" + (testing "non-empty vectors" (is (= [1 2 2 3 4 5] (list-ops/append [1 2] [2 3 4 5]))))) (deftest concatenate-test - (testing "empty list" + (testing "empty vector" (is (= [] (list-ops/concatenate [])))) - (testing "list of lists" + (testing "vector of vectors" (is (= [1 2 3 4 5 6] (list-ops/concatenate [[1 2] [3] [] [4 5 6]])))) - (testing "list of nested lists" + (testing "vector of nested vectors" (is (= [[1] [2] [3] [] [4 5 6]] (list-ops/concatenate [[[1] [2]] [[3]] [[]] [[4 5 6]]]))))) (deftest select-if-test - (testing "empty list" + (testing "empty vector" (is (= [] (list-ops/select-if (fn [x] (= (mod x 2) 1)) []))) - (testing "non-empty list" + (testing "non-empty vector" (is (= [1 3 5] (list-ops/select-if (fn [x] (= (mod x 2) 1)) [1 2 3 5])))))) (deftest length-test - (testing "empty list" + (testing "empty vector" (is (= 0 (list-ops/length [])))) - (testing "non-empty list" + (testing "non-empty vector" (is (= 4 (list-ops/length [1 2 3 4]))))) (deftest apply-to-each-test - (testing "empty list" + (testing "empty vector" (is (= [] (list-ops/apply-to-each (fn [x] (+ x 1)) [])))) - (testing "non-empty list" + (testing "non-empty vector" (is (= [2 4 6 8] (list-ops/apply-to-each (fn [x] (+ x 1)) [1 3 5 7]))))) (deftest foldl-test - (testing "empty list" + (testing "empty vector" (is (= 2 (list-ops/foldl (fn [acc el] (* el acc)) [] 2)))) - (testing "direction independent function applied to non-empty list" + (testing "direction independent function applied to non-empty vector" (is (= 15 (list-ops/foldl (fn [acc el] (+ el acc)) [1 2 3 4] 5)))) - (testing "direction dependent function applied to non-empty list" + (testing "direction dependent function applied to non-empty vector" (is (= 64 (list-ops/foldl (fn [acc el] (/ el acc)) [1 2 3 4] 24))))) (deftest foldr-test - (testing "empty list" + (testing "empty vector" (is (= 2 (list-ops/foldr (fn [acc el] (* el acc)) [] 2)))) - (testing "direction independent function applied to non-empty list" + (testing "direction independent function applied to non-empty vector" (is (= 15 (list-ops/foldr (fn [acc el] (+ el acc)) [1 2 3 4] 5)))) - (testing "direction dependent function applied to non-empty list" + (testing "direction dependent function applied to non-empty vector" (is (= 9 (list-ops/foldr (fn [acc el] (/ el acc)) [1 2 3 4] 24))))) (deftest reverse-order-test - (testing "empty list" + (testing "empty vector" (is (= [] (list-ops/reverse-order [])))) - (testing "non-empty list" + (testing "non-empty vector" (is (= [7 5 3 1] (list-ops/reverse-order [1 3 5 7])))) - (testing "list of lists is not flattened" + (testing "vector of vectors is not flattened" (is (= [[4 5 6] [] [3] [1 2]] (list-ops/reverse-order [[1 2] [3] [] [4 5 6]]))))) ;(clojure.test/run-tests) \ No newline at end of file From aeb8e538afba37662dd7f15f75c426c94089cf86 Mon Sep 17 00:00:00 2001 From: Kah Goh Date: Sun, 6 Oct 2024 08:24:19 +0800 Subject: [PATCH 09/12] Apply suggestions from code review Co-authored-by: Anastasios Chatzialexiou <16361161+tasxatzial@users.noreply.github.com> --- exercises/practice/list-ops/src/list_ops.clj | 9 +++++---- exercises/practice/list-ops/test/list_ops_test.clj | 2 -- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/exercises/practice/list-ops/src/list_ops.clj b/exercises/practice/list-ops/src/list_ops.clj index 6e4ae03cc..98bcedb58 100644 --- a/exercises/practice/list-ops/src/list_ops.clj +++ b/exercises/practice/list-ops/src/list_ops.clj @@ -8,12 +8,12 @@ (defn concatenate "Given a series of vectors, it combines all the vectors into one flattened vector" - [coll] + [colls] ;; your code goes here ) (defn select-if - "Given a predicate and a vector, it returns the vector of all items for which `predicate(item)` is True" + "Given a predicate and a vector, it returns the vector of all items for which predicate(item) is true" [pred coll] ;; your code goes here ) @@ -25,7 +25,7 @@ ) (defn apply-to-each - "Given a function and a vector, it returns the vector of the results of applying `function(item)` on all items" + "Given a function and a vector, it returns the vector of the results of applying function(item) on all items" [f coll] ;; your code goes here ) @@ -36,8 +36,9 @@ ;; your code goes here ) -(defn foldr [f coll init] +(defn foldr "Given a function, a vector, and an initial accumulator, it folds (reduces) each item into the accumulator from the right" + [f coll init] ;; your code goes here ) diff --git a/exercises/practice/list-ops/test/list_ops_test.clj b/exercises/practice/list-ops/test/list_ops_test.clj index a4598999d..2b269075a 100644 --- a/exercises/practice/list-ops/test/list_ops_test.clj +++ b/exercises/practice/list-ops/test/list_ops_test.clj @@ -61,5 +61,3 @@ (is (= [7 5 3 1] (list-ops/reverse-order [1 3 5 7])))) (testing "vector of vectors is not flattened" (is (= [[4 5 6] [] [3] [1 2]] (list-ops/reverse-order [[1 2] [3] [] [4 5 6]]))))) - -;(clojure.test/run-tests) \ No newline at end of file From 622a6beeaf2d53483233444b2c3c0d33735bee3c Mon Sep 17 00:00:00 2001 From: Anastasios Chatzialexiou <16361161+tasxatzial@users.noreply.github.com> Date: Sun, 6 Oct 2024 15:26:31 +0300 Subject: [PATCH 10/12] Add instructions.append --- exercises/practice/list-ops/.docs/instructions.append.md | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 exercises/practice/list-ops/.docs/instructions.append.md diff --git a/exercises/practice/list-ops/.docs/instructions.append.md b/exercises/practice/list-ops/.docs/instructions.append.md new file mode 100644 index 000000000..e226d470a --- /dev/null +++ b/exercises/practice/list-ops/.docs/instructions.append.md @@ -0,0 +1,8 @@ +# Instructions append + +## Implementation tips + +- The instructions use lists because they are synced with a shared repository to maintain consistency across tracks. + However, for this exercise in the Clojure track, you should assume that you are working with vectors instead of lists. +- It is important not to reuse existing Clojure built-in functions with similar functionality, as doing so would diminish the intended learning value of the exercise. + Some of these functions include `into`, `concat`, `cat`, `lazy-cat`, `mapcat`, `flatten`, `filter`, `filterv`, `remove`, `count`, `map`, `mapv`, `reduce`, `transduce`, `reverse`, and `rseq` from the **clojure.core** namespace. From 9fd1779f90d20421b99e3d2278e0e71d960fe46f Mon Sep 17 00:00:00 2001 From: Anastasios Chatzialexiou <16361161+tasxatzial@users.noreply.github.com> Date: Sun, 6 Oct 2024 15:51:32 +0300 Subject: [PATCH 11/12] also change 'series' to 'vector' --- exercises/practice/list-ops/src/list_ops.clj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/exercises/practice/list-ops/src/list_ops.clj b/exercises/practice/list-ops/src/list_ops.clj index 98bcedb58..28d30ea73 100644 --- a/exercises/practice/list-ops/src/list_ops.clj +++ b/exercises/practice/list-ops/src/list_ops.clj @@ -7,7 +7,7 @@ ) (defn concatenate - "Given a series of vectors, it combines all the vectors into one flattened vector" + "Given a vector of vectors, it combines all the vectors into one flattened vector" [colls] ;; your code goes here ) From 90768ca4dc2a7b37bb3b74c8d42d604d7a536bfe Mon Sep 17 00:00:00 2001 From: Kah Goh Date: Wed, 9 Oct 2024 07:30:35 +0800 Subject: [PATCH 12/12] Add tasxatzial as contributer --- exercises/practice/list-ops/.meta/config.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/exercises/practice/list-ops/.meta/config.json b/exercises/practice/list-ops/.meta/config.json index 98fbffdf3..1035f4f39 100644 --- a/exercises/practice/list-ops/.meta/config.json +++ b/exercises/practice/list-ops/.meta/config.json @@ -3,7 +3,8 @@ "bobbicodes" ], "contributors": [ - "kahgoh" + "kahgoh", + "tasxatzial" ], "files": { "solution": [