Inhalt
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á! 💪
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;
}