From c28720c978007bed7c65cb660328f021e2bce52a Mon Sep 17 00:00:00 2001 From: Ronaldo Ferreira de Lima Date: Fri, 22 Aug 2025 01:18:42 -0300 Subject: [PATCH] * add practice exercise: transpose --- config.json | 8 +++ .../practice/transpose/.docs/instructions.md | 61 ++++++++++++++++++ .../practice/transpose/.meta/config.json | 19 ++++++ .../practice/transpose/.meta/example.sql | 63 +++++++++++++++++++ exercises/practice/transpose/.meta/tests.toml | 46 ++++++++++++++ .../practice/transpose/create_fixture.sql | 11 ++++ .../practice/transpose/create_test_table.sql | 34 ++++++++++ exercises/practice/transpose/data.csv | 12 ++++ exercises/practice/transpose/transpose.sql | 7 +++ .../practice/transpose/transpose_test.sql | 40 ++++++++++++ 10 files changed, 301 insertions(+) create mode 100644 exercises/practice/transpose/.docs/instructions.md create mode 100644 exercises/practice/transpose/.meta/config.json create mode 100644 exercises/practice/transpose/.meta/example.sql create mode 100644 exercises/practice/transpose/.meta/tests.toml create mode 100644 exercises/practice/transpose/create_fixture.sql create mode 100644 exercises/practice/transpose/create_test_table.sql create mode 100644 exercises/practice/transpose/data.csv create mode 100644 exercises/practice/transpose/transpose.sql create mode 100644 exercises/practice/transpose/transpose_test.sql diff --git a/config.json b/config.json index a3f223b..367810b 100644 --- a/config.json +++ b/config.json @@ -402,6 +402,14 @@ "prerequisites": [], "difficulty": 8 }, + { + "slug": "transpose", + "name": "Transpose", + "uuid": "501d8d8b-4dd9-457d-866f-88120f046277", + "practices": [], + "prerequisites": [], + "difficulty": 8 + }, { "slug": "word-count", "name": "Word Count", diff --git a/exercises/practice/transpose/.docs/instructions.md b/exercises/practice/transpose/.docs/instructions.md new file mode 100644 index 0000000..6033af7 --- /dev/null +++ b/exercises/practice/transpose/.docs/instructions.md @@ -0,0 +1,61 @@ +# Instructions + +Given an input text output it transposed. + +Roughly explained, the transpose of a matrix: + +```text +ABC +DEF +``` + +is given by: + +```text +AD +BE +CF +``` + +Rows become columns and columns become rows. +See [transpose][]. + +If the input has rows of different lengths, this is to be solved as follows: + +- Pad to the left with spaces. +- Don't pad to the right. + +Therefore, transposing this matrix: + +```text +ABC +DE +``` + +results in: + +```text +AD +BE +C +``` + +And transposing: + +```text +AB +DEF +``` + +results in: + +```text +AD +BE + F +``` + +In general, all characters from the input should also be present in the transposed output. +That means that if a column in the input text contains only spaces on its bottom-most row(s), the corresponding output row should contain the spaces in its right-most column(s). + +[transpose]: https://en.wikipedia.org/wiki/Transpose diff --git a/exercises/practice/transpose/.meta/config.json b/exercises/practice/transpose/.meta/config.json new file mode 100644 index 0000000..25a63be --- /dev/null +++ b/exercises/practice/transpose/.meta/config.json @@ -0,0 +1,19 @@ +{ + "authors": [ + "jimmytty" + ], + "files": { + "solution": [ + "transpose.sql" + ], + "test": [ + "transpose_test.sql" + ], + "example": [ + ".meta/example.sql" + ] + }, + "blurb": "Take input text and output it transposed.", + "source": "Reddit r/dailyprogrammer challenge #270 [Easy].", + "source_url": "https://web.archive.org/web/20230630051421/https://old.reddit.com/r/dailyprogrammer/comments/4msu2x/challenge_270_easy_transpose_the_input_text/" +} diff --git a/exercises/practice/transpose/.meta/example.sql b/exercises/practice/transpose/.meta/example.sql new file mode 100644 index 0000000..b23ce34 --- /dev/null +++ b/exercises/practice/transpose/.meta/example.sql @@ -0,0 +1,63 @@ +DROP TABLE IF EXISTS jmatrix; +CREATE TEMPORARY TABLE jmatrix AS +SELECT lines, + ( + WITH to_line (line) AS ( + WITH RECURSIVE split_lines (string, line) AS ( + VALUES (REPLACE(lines, ' ', CHAR(7))||CHAR(10), NULL) + UNION ALL + SELECT SUBSTR(string, INSTR(string, CHAR(10)) + 1), + SUBSTR(string, 1, INSTR(string, CHAR(10)) - 1) + FROM split_lines + WHERE string <> '' + ) + SELECT line FROM split_lines WHERE line NOTNULL + ) + SELECT JSON_GROUP_ARRAY( + ( + WITH RECURSIVE to_letter (string, letter) AS ( + VALUES ( + PRINTF('%-*s', (SELECT MAX(LENGTH(line)) FROM to_line), line), + NULL + ) + UNION ALL + SELECT SUBSTR(string, 2), SUBSTR(string, 1, 1) + FROM to_letter + WHERE string <> '' + ) + SELECT JSON_GROUP_ARRAY(letter) + FROM to_letter + WHERE letter NOTNULL + ) + ) AS matrix + FROM to_line + ) AS matrix + FROM transpose +; + +UPDATE transpose SET result = '' WHERE lines = ''; + +UPDATE transpose + SET result = ( + WITH RECURSIVE to_transpose (jarray, idx, ncols, new_row) AS ( + VALUES ( + jmatrix.matrix, + 0, + JSON_ARRAY_LENGTH(JSON_EXTRACT(jmatrix.matrix, '$[0]')), + NULL + ) + UNION ALL + SELECT jarray, idx + 1, ncols, ( + SELECT GROUP_CONCAT(JSON_EXTRACT(j.value, PRINTF('$[%d]', idx)), '') + FROM JSON_EACH(jarray) j + ) + FROM to_transpose + WHERE idx < ncols + ) + SELECT GROUP_CONCAT(REPLACE(RTRIM(new_row,' '), CHAR(7), ' '), CHAR(10)) + FROM to_transpose + ) + FROM jmatrix + WHERE transpose.lines = jmatrix.lines + AND result ISNULL +; diff --git a/exercises/practice/transpose/.meta/tests.toml b/exercises/practice/transpose/.meta/tests.toml new file mode 100644 index 0000000..32e366f --- /dev/null +++ b/exercises/practice/transpose/.meta/tests.toml @@ -0,0 +1,46 @@ +# 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. + +[404b7262-c050-4df0-a2a2-0cb06cd6a821] +description = "empty string" + +[a89ce8a3-c940-4703-a688-3ea39412fbcb] +description = "two characters in a row" + +[855bb6ae-4180-457c-abd0-ce489803ce98] +description = "two characters in a column" + +[5ceda1c0-f940-441c-a244-0ced197769c8] +description = "simple" + +[a54675dd-ae7d-4a58-a9c4-0c20e99a7c1f] +description = "single line" + +[0dc2ec0b-549d-4047-aeeb-8029fec8d5c5] +description = "first line longer than second line" + +[984e2ec3-b3d3-4b53-8bd6-96f5ef404102] +description = "second line longer than first line" + +[eccd3784-45f0-4a3f-865a-360cb323d314] +description = "mixed line length" + +[85b96b3f-d00c-4f80-8ca2-c8a5c9216c2d] +description = "square" + +[b9257625-7a53-4748-8863-e08e9d27071d] +description = "rectangle" + +[b80badc9-057e-4543-bd07-ce1296a1ea2c] +description = "triangle" + +[76acfd50-5596-4d05-89f1-5116328a7dd9] +description = "jagged triangle" diff --git a/exercises/practice/transpose/create_fixture.sql b/exercises/practice/transpose/create_fixture.sql new file mode 100644 index 0000000..6edbb86 --- /dev/null +++ b/exercises/practice/transpose/create_fixture.sql @@ -0,0 +1,11 @@ +DROP TABLE IF EXISTS transpose; +CREATE TABLE transpose ( + lines TEXT NOT NULL, + result TEXT +); + +.mode csv +.import ./data.csv transpose + +UPDATE transpose SET result = NULL; +UPDATE transpose SET lines = REPLACE(lines, '\n', CHAR(10)); diff --git a/exercises/practice/transpose/create_test_table.sql b/exercises/practice/transpose/create_test_table.sql new file mode 100644 index 0000000..a36eb8b --- /dev/null +++ b/exercises/practice/transpose/create_test_table.sql @@ -0,0 +1,34 @@ +DROP TABLE IF EXISTS tests; +CREATE TABLE IF NOT EXISTS tests ( + -- uuid and description are taken from the test.toml file + uuid TEXT PRIMARY KEY, + description TEXT NOT NULL, + -- The following section is needed by the online test-runner + status TEXT DEFAULT 'fail', + message TEXT, + output TEXT, + test_code TEXT, + task_id INTEGER DEFAULT NULL, + -- Here are columns for the actual tests + lines TEXT NOT NULL, + expected TEXT NOT NULL +); + +INSERT INTO tests (uuid, description, lines, expected) +VALUES + ('404b7262-c050-4df0-a2a2-0cb06cd6a821', 'empty string', '', ''), + ('a89ce8a3-c940-4703-a688-3ea39412fbcb', 'two characters in a row', 'A1', 'A\n1'), + ('855bb6ae-4180-457c-abd0-ce489803ce98', 'two characters in a column', 'A\n1', 'A1'), + ('5ceda1c0-f940-441c-a244-0ced197769c8', 'simple', 'ABC\n123', 'A1\nB2\nC3'), + ('a54675dd-ae7d-4a58-a9c4-0c20e99a7c1f', 'single line', 'Single line.', 'S\ni\nn\ng\nl\ne\n \nl\ni\nn\ne\n.'), + ('0dc2ec0b-549d-4047-aeeb-8029fec8d5c5', 'first line longer than second line', 'The fourth line.\nThe fifth line.', 'TT\nhh\nee\n \nff\noi\nuf\nrt\nth\nh \n l\nli\nin\nne\ne.\n.'), + ('984e2ec3-b3d3-4b53-8bd6-96f5ef404102', 'second line longer than first line', 'The first line.\nThe second line.', 'TT\nhh\nee\n \nfs\nie\nrc\nso\ntn\n d\nl \nil\nni\nen\n.e\n .'), + ('eccd3784-45f0-4a3f-865a-360cb323d314', 'mixed line length', 'The longest line.\nA long line.\nA longer line.\nA line.', 'TAAA\nh \nelll\n ooi\nlnnn\nogge\nn e.\nglr\nei \nsnl\ntei\n .n\nl e\ni .\nn\ne\n.'), + ('85b96b3f-d00c-4f80-8ca2-c8a5c9216c2d', 'square', 'HEART\nEMBER\nABUSE\nRESIN\nTREND', 'HEART\nEMBER\nABUSE\nRESIN\nTREND'), + ('b9257625-7a53-4748-8863-e08e9d27071d', 'rectangle', 'FRACTURE\nOUTLINED\nBLOOMING\nSEPTETTE', 'FOBS\nRULE\nATOP\nCLOT\nTIME\nUNIT\nRENT\nEDGE'), + ('b80badc9-057e-4543-bd07-ce1296a1ea2c', 'triangle', 'T\nEE\nAAA\nSSSS\nEEEEE\nRRRRRR', 'TEASER\n EASER\n ASER\n SER\n ER\n R'), + ('76acfd50-5596-4d05-89f1-5116328a7dd9', 'jagged triangle', '11\n2\n3333\n444\n555555\n66666', '123456\n1 3456\n 3456\n 3 56\n 56\n 5'); + +UPDATE tests + SET lines = REPLACE(lines, '\n', CHAR(10)), + expected = REPLACE(expected, '\n', CHAR(10)); diff --git a/exercises/practice/transpose/data.csv b/exercises/practice/transpose/data.csv new file mode 100644 index 0000000..8cf9ff1 --- /dev/null +++ b/exercises/practice/transpose/data.csv @@ -0,0 +1,12 @@ +"", +"A1", +"A\n1", +"ABC\n123", +"Single line.", +"The fourth line.\nThe fifth line.", +"The first line.\nThe second line.", +"The longest line.\nA long line.\nA longer line.\nA line.", +"HEART\nEMBER\nABUSE\nRESIN\nTREND", +"FRACTURE\nOUTLINED\nBLOOMING\nSEPTETTE", +"T\nEE\nAAA\nSSSS\nEEEEE\nRRRRRR", +"11\n2\n3333\n444\n555555\n66666", diff --git a/exercises/practice/transpose/transpose.sql b/exercises/practice/transpose/transpose.sql new file mode 100644 index 0000000..12af845 --- /dev/null +++ b/exercises/practice/transpose/transpose.sql @@ -0,0 +1,7 @@ +-- Schema: +-- CREATE TABLE transpose ( +-- lines TEXT NOT NULL, +-- result TEXT +-- ); +-- +-- Task: update the transpose table and set the result based on the lines. diff --git a/exercises/practice/transpose/transpose_test.sql b/exercises/practice/transpose/transpose_test.sql new file mode 100644 index 0000000..e83e044 --- /dev/null +++ b/exercises/practice/transpose/transpose_test.sql @@ -0,0 +1,40 @@ +-- Create database: +.read ./create_fixture.sql + +-- Read user student solution and save any output as markdown in user_output.md: +.mode markdown +.output user_output.md +.read ./transpose.sql +.output + +-- Create a clean testing environment: +.read ./create_test_table.sql + +-- Comparison of user input and the tests updates the status for each test: +UPDATE tests +SET status = 'pass' +FROM (SELECT lines, result FROM transpose) AS actual +WHERE (actual.lines, actual.result) = (tests.lines, tests.expected); + +-- Update message for failed tests to give helpful information: +UPDATE tests +SET message = ( + 'Result for "' + || tests.lines + || '"' + || ' is <' || COALESCE(actual.result, 'NULL') + || '> but should be <' || tests.expected || '>' +) +FROM (SELECT lines, result FROM transpose) AS actual +WHERE actual.lines = tests.lines AND tests.status = 'fail'; + +-- Save results to ./output.json (needed by the online test-runner) +.mode json +.once './output.json' +SELECT description, status, message, output, test_code, task_id +FROM tests; + +-- Display test results in readable form for the student: +.mode table +SELECT description, status, message +FROM tests;