Formatowanie liczb

Jozdowska Edyta · 03 Luty 2020

Niekiedy w bitwach programowania nie ma opisu zadania. Są jedynie pokazane testy i należy na ich podstawie domyśleć się, co należy zrobić. Na poniższym zadaniu poległam. Do końca nie wiedziałam o co chodzi. Oczywiście po testach widziałam, że dotyczy ono różnego zapisu liczb. 15 minut jednak było zbyt krótkim czasem dla mnie, by znaleźć rozwiązanie. A okazało się banalne.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# TEST 1
	INPUT: 15
	OUTPUT: xfb1111o17

# TEST 2
	INPUT: 0
	OUTPUT: x0b0o0

# TEST 3
	INPUT: 328
	OUTPUT: x148b101001000o510

# TEST 4
	INPUT: 831039
	OUTPUT: xcae3fb11001010111000111111o3127077

Na powyższej podstawie należało podać kod, który przekształci liczbę w odpowiednio zakodowany ciąg. Dopiero po skończonej bitwie, kiedy można zobaczyć kod innych, o ile go udostępnią - dowiedziałam się o co chodziło. Rozłóżmy ten ciąg na czynniki pierwsze, składa się z cyfr i liter.

Najczęściej występującymi literami są: x, b i o. xfb1111o17, x0b0o0, x148b101001000o510, powtarzają się w każdym ciągu. x = HEX, b = BIN i o = OCT, co odpowiada zapisowi liczby w kodzie 16-szesnastkowym, 2-dwójkowym i 8-ósemkowym. Tak, jak ktoś wskaże rozwiązanie, wydaje się to tak oczywiste :smile:

JavaScript

Kod JS na rozwiązanie - kilka podejść. Ponieważ zawsze mamy jakiś wybór przy kodowaniu i kilka sposobów rozwiązania.

1
2
3
4
5
6
7
//z Map
n = 15;
k= [['x',16],['b',2],['o',16]];

console.log(k.map((a,b)=>a[0]+(n*1).toString(a[1])).join(''))

// OUTPUT: xfb1111o17

Niby założenie dobre, ale zastanówmy się. Tablica k jest tak kiepsko napisana, że nie chciałabym jej zobaczyć w żadnym kodzie. Chcę użyć k = {'x':16,'b':2,'o':16}. Powtórzmy powyższy kod, dostosowując go do danej wejściowej k.

1
2
3
4
5
n = 15;
k = {'x':16,'b':2,'o':16}
console.log(Object.entries(k).map((a,b)=>a[0]+n.toString(a[1]+'')).join(''))

// OUTPUT: xfb1111o17

Object.entries(k) tworzy dokładnie taką samą tablicę [['x',16],['b',2],['o',16]] z obiektu {'x':16,'b':2,'o':16}. Jak dla mnie jednak trochę za długo, jak na taką prostą oeprację. Chcemy interować po obiekcie k więc po co przekształcać go na array? Kod do przepisania!

1
2
3
4
5
6
7
8
9
n=15;
s='';
k={x:16,b:2,o:8};
for(a in k){
	s += a + n.toString(k[a])
}
console.log(s)

// OUTPUT: xfb1111o17

Szybciej prawda :) Tylko czy do tego zadania potrzebna nam jest loop’a.

1
2
n=15;
console.log(`x`+n.toString('16')+`b`+n.toString('2')+`o`+n.toString('8'));

Patrząc na całość, kod ze zwykłym loop na obiekcie, najbardziej do mnie przemawia.

Python

Zobaczmy Pythona, z zastosowaniem funkcji wbudowanych bin(), hex() i oct()

1
2
3
4
n=15
print('h'+hex(n)[-1:]+bin(n)+'o'+oct(n)[-1:])

# OUTPUT: xfb1111o17

Jak dla mnie to nie jest po pytonowsku, mimo, że w Python pisane :smile: Idea Pythona to prostota. Wiedząc, że od wersji Pythona 3.6 wprowadzono nowy sposób formatowania liczb poprzez f{liczba:format} powyższe możemy zapisać po prostu:

1
2
3
4
n=15
print(f'x{n:x}b{n:b}o{n:o}')

# OUTPUT: xfb1111o17

Teraz dla mnie jest po pythonowku. I to rozwiązanie przyjmuję :smile:

PHP

Czas na PHP. Wpierw z wykorzystaniem funkcji wbudowanych dechex(), decbin() i decoct()

1
2
3
4
5
$n=15;

echo "x".dechex($n)."b".decbin($n)."o".decoct($n);

// OUTPUT: xfb1111o17

Powyższy kod jest czytelny, ale za długi, na pewno da się napisać inaczej :smile: PHP z fromatowaniem:

1
2
3
4
5
$n=15;

printf("x%xb%bo%o",$n,$n,$n);

// OUTPUT: xfb1111o17

PHP, tak samo jak python ma możliwość przedstawiania danych w odpowiednich formatach. Służą do tego różne funkcje printf(), sprintf() i jeszcze parę. Niby wszystko jest poprawnie, ale denerwuje mnie powtórzenie trzy razy $n. Da się inaczej:

1
2
$n=15;
printf('x%1$xb%1$bo%1$o',$n);

Do printf() możemy wchodzić z kilkoma argumentami, każdy otrzymuje swój numer. Wskazujemy go za pomocą albo liczby pożądkowej, jak w tym przypadku %1, albo po jej formacie czyli dla liczby to %d. Wszystko zależy jak ułożymy swój input. W tym przypadku użycie %d będzie skutkowało błędem:

Warning: printf(): Too few arguments in […][…] on line xxx

Brrr, jest to najbardziej zaciemniona wersja w PHP :rofl:.

Przejdźmy do zetsawienia długości:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
// PYTHON No2 => 28
console.log(`print(f'x{n:x}b{n:b}o{n:o}')`.length)

// PHP No2 => 29
console.log(`printf("x%xb%bo%o",$n,$n,$n);`.length)

// PHP No3 => 29
console.log(`printf('x%1$xb%1$bo%1$o',$n);`.length)

// PYTHON No1 => 45
console.log(`print('h'+hex(n)[-1:]+bin(n)+'o'+oct(n)[-1:])`.length)

// PHP No1 => 50
console.log(`echo "x".dechex($n)."b".decbin($n)."o".decoct($n);`.length)

// JAVASCRIPT No3 => 69
console.log(`s='';k={x:16,b:2,o:8}for(a in k){s+=a+n.toString(k[a])}
console.log(s)`.length)

// JAVASCRIPT No4 => 74
console.log(`console.log('x'+n.toString('16')+'b'+n.toString('2')+
'o'+n.toString('8'));`.length)

// JAVASCRIPT No1 => 91
console.log(`k=[['x',16],['b',2],['o',16]];console.log(k.map((a,b)=>a[0]+(n*1)
.toString(a[1])).join(''))`.length)

// JAVASCRIPT No2 => 98 - o dziwo, choć kod jest ładniejszy
console.log(`k='x':16,'b':2,'o':16}console.log(Object.entries(k).map((a,b)=>a[0]
+n.toString(a[1]+'')).join(''))`.length)

W moim zestawieniu długości znów Python wygrywa. Ma on przewagę nad PHP znów o jeden znak i pewnie trudno zgadnąć o który ; Należy pamiętać, że w PHP mamy zapis zmiennych $, co kod wydłuża, też o dodatkowy znak :rofl: - wnioski pozostawiam do wyciągniecią samemu :wink:

Przygotowując po raz kolejny zestawienie, naszła mnie myśl, choć niektórzy się może obrażą na mnie. PHP jest badzo podobny do pythona. Przynajmniej w niektórych kwestiach.

Jozdowska Edyta * FullStack Developer

Pisanie kodu jest moją pasją. Zajmuję się tym od przeszło 10 lat, z większą lub mniejszą intensywnością.
Piszę kod w PHP, JS, SCSS i Python. Nie stronię też od poznawania nowych, lub jak kto woli starych rozwiązań jak Jekyll oraz innych języków np. Java.

więcej o mnie