Codewars Lösung | Split all even numbers to odd ones in different ways


coden
Codewars. Achieve mastery through challenge.
Daniel Kaser|16. September 2024
5 min.

Inhalt

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

Die Fakten:

Plattform:codewars.com
Name:Split all even numbers to odd ones in different ways
Level:6 kyu
Sprache:TypeScript

Beschreibung:

#Split all even numbers to odd ones in different ways

Your task is to split all even numbers from an array to odd ones. So your method has to return a new array with only odd numbers.

For "splitting" the numbers there are four ways.

0 -> Split into two odd numbers, that are closest to each other.
     (e.g.: 8 -> 3,5)
1 -> Split into two odd numbers, that are most far from each other.
     (e.g.: 8 -> 1,7)
2 -> All new odd numbers from the splitting should be equal and the maximum possible number.
     (e.g.: 8 -> 1, 1, 1, 1, 1, 1, 1, 1)
3 -> Split into 1s.
     (e.g.: 8 -> 1, 1, 1, 1, 1, 1, 1, 1)
The new numbers (from the splitting) have always to be in ascending order.
So in the array every even number is replaced by the new odd numbers from the splitting.

Your method will get as parameters the input-array and the number of the way for splitting the even numbers.

Some Examples

[1,10,1,3],0 -> [1,5,5,1,3]
[1,10,1,3],1 -> [1,1,9,1,3]
[1,10,1,3],2 -> [1,5,5,1,3]
[1,10,1,3],3 -> [1,1,1,1,1,1,1,1,1,1,1,1,3]

[1,1,3,8],0 -> [1,1,3,3,5]
[1,1,3,8],1 -> [1,1,3,1,7]
[1,1,3,8],2 -> [1,1,3,1,1,1,1,1,1,1,1]
[1,1,3,8],3 -> [1,1,3,1,1,1,1,1,1,1,1]

The array will never be null and will always contain only integer numbers > 0. Also your result-array must contain only integer numbers > 0. The way-parameter will always be between inclusive 0 and inclusive 3 (0,1,2,3).

You must not change the input-array!




Have fun coding it and please don't forget to vote and rank this kata! :-)

I have also created other katas. Take a look if you enjoyed this kata!

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

Da wir 4 klare Fälle haben, können wir überlegen hier 4 Hilfsfunktionen zu erstellen. Das macht den Code wunderbar lesbar.

Schritt 2

Außerdem noch eine, die prüft, ob die aktuelle Zahl gerade ist.

Schritt 3

Fall 1:

2 Zahlen möglichst dicht aneinander:

Wir prüfen, ob die Hälfte der geraden Input-Zahl auch gerade ist.

Schritt 4

Wenn ja, geben wir ein Array mit den beiden Zahlen + bzw. - 1 zurück.

Schritt 5

Ansonsten geben wir ein Array mit 2 Hälften zurück.

Schritt 6

Fall 2:

2 Zahlen möglichst weit auseinander:

Hier geben wir einfach ein Array zurück mit 1 und der Input-Zahl minus 1.

Schritt 7

Fall 3:

Gleiche Zahlen und so groß wie möglich:

Hier brauchen wir einen Loop.

Schritt 8

Wir teilen die Input-Zahl solange durch 2, bis wir eine ungerade Zahl bekommen.

Schritt 9

Dann geben wir ein Array zurück, das so lang ist, wie die erhaltene ungerade Zahl in die Input-Zahl rein passt und füllen es mit diesen ungeraden Zahlen.

Schritt 10

Fall 4:

Alles Einsen:

Hier geben wir einfach ein Array zurück, das so lang ist wie die Input-Zahl und füllen es mit Einsen.

Schritt 11

Dann können wir uns endlich an die Hauptfunktion machen! 🕺

Schritt 12

Hier loopen wir durch alle Zahlen im Input-Array.

Schritt 13

Wenn die aktuelle Zahl ungerade ist, geben wir sie unverändert zurück.

Schritt 14

Ansonsten prüfen wir den Fall/way.

Schritt 15

Je nach Fall geben wir das Ergebnis unserer entsprechenden Hilfsfunktion zurück.

Schritt 16

Zum Schluss geben wir das Gesamtergebnis zurück.

Code

Geil. Übersetzen wir unseren Pseudo-Code in TypeScript:

Lösungsschritte
Zuerst die Hilfsfunktion, die prüft, ob es sich um eine gerade Zahl handelt:
function isEven(num: number): boolean {
  return num % 2 === 0;
}
Dann die Hilfsfunktion, die die beiden ungeraden Zahlen zurückgibt, die sich am nächsten sind:
function splitEvenNumToOddsClosestToEachOther(num: number): number[] {
  const half = num / 2;
  return isEven(half) ? [half - 1, half + 1] : [half, half];
}
Jetzt die Hilfsfunktion, die die beiden ungeraden Zahlen zurückgibt, die am weitesten voneinander entfernt sind:
function splitEvenNumToOddsFarestToEachOther(num: number): number[] {
  return [1, num - 1];
}
Als Drittes die Funktion, die die größtmöglichen gleichen ungeraden Zahlen zurück gibt:
function splitEvenNumToEqualOddsAndMaxPossible(num: number): number[] {
  let half = num / 2;
  while (isEven(half)) half /= 2;
  return Array(num / half).fill(half);
}
Und die letzte Hilfsfunktion, die nur Einsen zurück gibt:
function splitEvenNumToAllOnes(num: number): number[] {
  return Array(num).fill(1);
}

Dann endlich die Hauptfunktion! 😅

Hier die erste Zeile meiner Hauptfunktion:
export function splitAllEvenNumbers(nums: number[], way: number): number[] {
Jetzt der Loop:
  return nums.flatMap((num) => {

Da wir am Schluss Arrays ins Ergebnis-Array zurück bekommen, können wir diese Arrays hier mit .flatMap() im Loop direkt auflösen.

Und da wir nach dem Loop fertig sind, können wir unser return hier direkt davor setzen.

Dann die Logik. Wenn die aktuelle Zahl ungerade ist, geben wir sie unverändert ins Array zurück:
if (!isEven(num)) return num;
Ansonsten führen wir eine unserer Hilfsfunktionen aus, basierend auf der way-Variablen:
    if (way === 0) return splitEvenNumToOddsClosestToEachOther(num);
    if (way === 1) return splitEvenNumToOddsFarestToEachOther(num);
    if (way === 2) return splitEvenNumToEqualOddsAndMaxPossible(num);
    return splitEvenNumToAllOnes(num);
  });
}

Das Ganze geht hier wunderbar ohne else und ist so meiner Meinung nach viel übersichtlicher.

Alternativ kannst Du hier natürlich auch ein switch-Statement verwenden. Bin ich persönlich aber kein Fan von...

Voilá! 💪

Fragen?

Komplettlösung
export function splitAllEvenNumbers(nums: number[], way: number): number[] {
  return nums.flatMap((num) => {
    if (!isEven(num)) return num;
    if (way === 0) return splitEvenNumToOddsClosestToEachOther(num);
    if (way === 1) return splitEvenNumToOddsFarestToEachOther(num);
    if (way === 2) return splitEvenNumToEqualOddsAndMaxPossible(num);
    return splitEvenNumToAllOnes(num);
  });
}

function splitEvenNumToOddsClosestToEachOther(num: number): number[] {
  const half = num / 2;
  return isEven(half) ? [half - 1, half + 1] : [half, half];
}

function splitEvenNumToOddsFarestToEachOther(num: number): number[] {
  return [1, num - 1];
}

function splitEvenNumToEqualOddsAndMaxPossible(num: number): number[] {
  let half = num / 2;
  while (isEven(half)) half /= 2;
  return Array(num / half).fill(half);
}

function splitEvenNumToAllOnes(num: number): number[] {
  return Array(num).fill(1);
}

function isEven(num: number): boolean {
  return num % 2 === 0;
}

Feedback

Schreib mir!