Codewars Lösung | Moves in squared strings (III)


coden
Codewars. Achieve mastery through challenge.
Daniel Kaser|30. März 2024
4 min.

Inhalt

  1. Die Fakten
  2. Beschreibung
  3. Lösung
    1. Pseudo-Code
    2. Code
  4. Feedback

Die Fakten:

Plattform:codewars.com
Name:Moves in squared strings (III)
Level:6 kyu
Sprache:TypeScript

Beschreibung:

You are given a string of n lines, each substring being n characters long: For example:

s = "abcd\nefgh\nijkl\nmnop"

We will study some transformations of this square of strings.

Let's now transform this string!

  • Symmetry with respect to the main diagonal: diag_1_sym (or diag1Sym or diag-1-sym)
diag_1_sym(s) => "aeim\nbfjn\ncgko\ndhlp"
  • Clockwise rotation 90 degrees: rot_90_clock (or rot90Clock or rot-90-clock)
rot_90_clock(s) => "miea\nnjfb\nokgc\nplhd"
  • selfie_and_diag1(s) (or selfieAndDiag1 or selfie-and-diag1) It is initial string + string obtained by symmetry with respect to the main diagonal.
s = "abcd\nefgh\nijkl\nmnop" --> 
"abcd|aeim\nefgh|bfjn\nijkl|cgko\nmnop|dhlp"

or printed for the last:

selfie_and_diag1
abcd|aeim
efgh|bfjn
ijkl|cgko 
mnop|dhlp

Task:

  • Write these functions diag_1_sym, rot_90_clock, selfie_and_diag1

and

  • high-order function oper(fct, s) where

  • fct is the function of one variable f to apply to the string s (fct will be one of diag_1_sym, rot_90_clock, selfie_and_diag1)

Examples:

s = "abcd\nefgh\nijkl\nmnop"
oper(diag_1_sym, s) => "aeim\nbfjn\ncgko\ndhlp"
oper(rot_90_clock, s) => "miea\nnjfb\nokgc\nplhd"
oper(selfie_and_diag1, s) => "abcd|aeim\nefgh|bfjn\nijkl|cgko\nmnop|dhlp"

Notes:

  • The form of the parameter fct in oper changes according to the language. You can see each form according to the language in "Your test cases".

  • It could be easier to take these katas from number (I) to number (IV)

  • Bash Note: The output strings should be separated by \r instead of \n. See "Sample Tests".

Quelle: codewars.com

Lösung

Pseudo-Code

Wie immer gibt's reichlich Varianten, hier ist eine meiner.

Erst die Lösungsschritte in Pseudo-Code. Los geht’s:

Lösungsschritte
Schritt 1

Für die Diagonal-Version erstelle ich mir zuerst ein Ergebnis-Array, das genauso lang ist, wie die "Wörter" im Input und fülle es mit leeren Strings.

Schritt 2

Dann loope ich durch die "Wörter".

Schritt 3

Und dann noch mal durch jedes "Wort".

Schritt 4

Jedes Zeichen hänge ich an den String mit dem gleichen Index im Ergebnis-Array.

Schritt 5

Für die Rotierte-Version erstelle ich erst die Diagonal-Version.

Schritt 6

Dann drehe ich jedes "Wort" einfach um.

Schritt 7

Für die Selfie-und-Diagonal-Version erstelle ich auch wieder erst die Diagonal-Version.

Schritt 8

Dann gebe ich einfach das Original-Wort, gefolgt von Pipe und Diagonal-Wort zurück.

Schritt 9

In der Oper-Funktion gebe ich einfach die Input-Funtion mit dem Input-String als Argument zurück.

Code

Na denn... übersetzen wir unseren Pseudo-Code in TypeScript:

Lösungsschritte
Die erste Zeile meiner Diagonal-Funktion (ich habe in jeder Funktion strng zu str umbenannt):
export function diag1Sym(str: string): string {
Dann erstellen wir das Ergebnis-Array mit der Länge bzw. Anzahl der "Wörter" im Input-String:
const words = str.split("\n");
const result: string[] = Array(words.length).fill("");
Jetzt der Loop durch die "Wörter":
  words.forEach((word) =>
Dann der Loop durch die Zeichen jedes einzelnen Wortes:
    word.split("").forEach((char, i) => (result[i] += char))
  );

Jedes Zeichen hängen wir an den korrespondierenden String im Ergebnis-Array. Dafür nutzen wir den Index i.

Zum Schluss noch das Ergebnis-Array als String zurückgeben:
  return result.join("\n");
}

Als nächstes kümmern wir uns um die Rotations-Version.

Hier die erste Zeile meiner Rotations-Funktion:
export function rot90Clock(str: string): string {
Das kriegen wir mit Method-Chaining hin:
  return diag1Sym(str)
    .split("\n")
    .map((word) => word.split("").reverse().join(""))
    .join("\n");
}

Erst wenden wir unsere Diagonal-Funktion auf den Input-String an. Dann drehen wir die einzelnen "Wörter" einfach um.

Weiter geht’s mit der Selfie-Diagonal-Funktion:

Hier die erste Zeile der Selfie-Diagonal-Funktion:
export function selfieAndDiag1(str: string): string {
Dann wenden wir wieder unsere Diagonal-Funktion an:
const diagWords = diag1Sym(str).split("\n");

Außerdem splitte ich hier die "Wörter" in ein Array und speichere es in einer Variablen.

Den Rest kriegen wir wieder mit Method-Chaining hin:
  return str
    .split("\n")
    .map((word, i) => `${word}|${diagWords[i]}`)
    .join("\n");
}

Hier ersetzen wir jedes "Wort" im Input-String mit dem Original-Wort, einer Pipe und dem entsprechenden Diagonal-Wort.

Zum Schluss nur noch die Oper-Funktion.

Die erste der Oper-Funktion Zeile:
export function oper(fct: (str: string) => string, str: string): string {
Wir geben einfach die Input-Funktion mit dem Input-String als Argument zurück:
  return fct(str);
}
Voilá! 💪

Fragen?

Komplettlösung
export function diag1Sym(str: string): string {
  const words = str.split("\n");
  const result: string[] = Array(words.length).fill("");

  words.forEach((word) =>
    word.split("").forEach((char, i) => (result[i] += char)),
  );

  return result.join("\n");
}

export function rot90Clock(str: string): string {
  return diag1Sym(str)
    .split("\n")
    .map((word) => word.split("").reverse().join(""))
    .join("\n");
}

export function selfieAndDiag1(str: string): string {
  const diagWords = diag1Sym(str).split("\n");

  return str
    .split("\n")
    .map((word, i) => `${word}|${diagWords[i]}`)
    .join("\n");
}

export function oper(fct: (str: string) => string, str: string): string {
  return fct(str);
}

Feedback

Schreib mir!