Chciałbym sformatować następujące liczby w liczby obok nich za pomocą java:
1000 to 1k
5821 to 5.8k
10500 to 10k
101800 to 101k
2000000 to 2m
7800000 to 7.8m
92150000 to 92m
123200000 to 123m
Liczba po prawej stronie będzie długa lub całkowita, a liczba po lewej będzie łańcuchem. Jak mam do tego podejść. Zrobiłem już mały algorytm do tego, ale pomyślałem, że może być już wymyślone coś, co robi fajniejszą robotę i nie wymaga dodatkowych testów, jeśli zacznę mieć do czynienia z miliardami i bilionami :)
Dodatkowe wymagania:
- Format powinien mieć maksymalnie 4 znaki
- Powyższe oznacza, że 1,1k jest OK 11,2k nie jest. To samo dla 7,8 m jest OK 19,1 m nie jest. Tylko jedna cyfra przed kropką dziesiętną może mieć kropkę dziesiętną. Dwie cyfry przed kropką dziesiętną oznaczają brak cyfr po przecinku.
- Nie jest konieczne zaokrąglanie. (Liczby wyświetlane z dołączonymi k i m są raczej miernikiem analogowym wskazującym przybliżenie, a nie dokładny artykuł logiki. Dlatego zaokrąglanie jest nieistotne głównie ze względu na naturę zmiennej, ponieważ może zwiększyć lub zmniejszyć kilka cyfr, nawet gdy patrzysz na wynik zapisany w pamięci podręcznej.)
java
number-formatting
Mat B.
źródło
źródło
No rounding is necessary
tym kryje, wydaje mi się absurdalna. Czy to tylko skomplikowanie sprawy? Czy nie lepiej byłoby to przeformułowaćRounding is not necessary, but welcome
?Odpowiedzi:
Oto rozwiązanie, które działa dla każdej długiej wartości i które uważam za całkiem czytelne (podstawowa logika jest wykonana w trzech dolnych wierszach
format
metody).Wykorzystuje,
TreeMap
aby znaleźć odpowiedni przyrostek. Jest zaskakująco wydajniejsze niż poprzednie rozwiązanie, które napisałem, które wykorzystywało tablice i było trudniejsze do odczytania.Kod testowy
źródło
-5821
powinien być sformatowany jako-5k
, a nie jako-5.8k
.-
aby zachować tę samą liczbę cyfr znaczących. Są inne opcje ...Wiem, to wygląda bardziej jak program w C, ale jest super lekki!
Wyprowadza:
źródło
Oto rozwiązanie, które korzysta z notacji inżynierskiej DecimalFormat:
Wynik:
źródło
Potrzebujesz poprawy, ale: StrictMath na ratunek!
Możesz umieścić sufiks w łańcuchu lub tablicy i pobrać je na podstawie mocy lub coś w tym rodzaju.
Podziałem można również zarządzać wokół mocy, myślę, że prawie wszystko dotyczy wartości mocy. Mam nadzieję, że to pomoże!
wyjścia:
źródło
Problemy z aktualnymi odpowiedziami
Rozwiązanie Java
To rozwiązanie (rozszerzenie tej odpowiedzi ) rozwiązuje powyższe problemy.
Groovy Solution
Rozwiązanie zostało pierwotnie napisane w Groovy, jak pokazano poniżej.
Testy (Groovy)
Testy są napisane w Groovy, ale można ich użyć do weryfikacji klasy Java lub Groovy (ponieważ obie mają tę samą nazwę i API).
źródło
Plik ICU lib ma formatowania reguł opartych na liczbach, które mogą być używane do liczby spellout itp myślę użyciu ICU nie daje czytelny i maintanable rozwiązanie.
[Stosowanie]
Właściwa klasa to RuleBasedNumberFormat. Sam format może być przechowywany jako oddzielny plik (lub jako stała String, IIRC).
Przykład z http://userguide.icu-project.org/formatparse/numbers
Ta sama strona pokazuje cyfry rzymskie, więc myślę, że twój przypadek też powinien być możliwy.
źródło
CompactDecimalFormat
. Poziom API 24+W Javie-12 + możesz
NumberFormat.getCompactNumberInstance
formatować liczby. Możesz utworzyćNumberFormat
pierwszy plik jakoa następnie użyj go do
format
:źródło
Ważne: przesyłanie odpowiedzi na
double
nie powiedzie się w przypadku liczb takich jak99999999999999999L
i zwraca100P
zamiast,99P
ponieważdouble
używaIEEE
standardu :To rozwiązanie odcina niechciane cyfry i działa dla wszystkich
long
wartości . Prosta, ale wydajna implementacja (porównanie poniżej). -120k nie może być wyrażone za pomocą 4 znaków, nawet -0,1M jest za długie, dlatego dla liczb ujemnych 5 znaków musi być w porządku:Test
else if
na początku jest konieczny, ponieważ min jest,-(2^63)
a maksimum jest,(2^63)-1
a zatem przypisanienumber = -number
nie powiedzie się, jeślinumber == Long.MIN_VALUE
. Jeśli musimy zrobić czek, możemy równie dobrze uwzględnić jak najwięcej liczb, zamiast tylko sprawdzaćnumber == Long.MIN_VALUE
.Porównanie tej implementacji z tą, która uzyskała najwięcej głosów pozytywnych (podobno jest obecnie najszybsza) pokazało, że jest ona ponad 5 razy szybsza (zależy to od ustawień testowych, ale przy większej liczbie liczb zysk jest większy i ta implementacja ma aby wykonać więcej kontroli, ponieważ obsługuje wszystkie przypadki, więc jeśli drugi zostanie naprawiony, różnica będzie jeszcze większa). Jest tak szybki, ponieważ nie ma operacji zmiennoprzecinkowych, logarytmu, potęgi, rekursji, wyrażenia regularnego, wyrafinowanych elementów formatujących i minimalizacji ilości tworzonych obiektów.
Oto program testowy:
Możliwe dane wyjściowe:
2309 vs. 11591
(mniej więcej to samo, gdy używamy tylko liczb dodatnich i znacznie bardziej ekstremalne podczas odwracania kolejności wykonywania, może ma to coś wspólnego z usuwaniem elementów bezużytecznych)źródło
Oto krótka implementacja bez rekursji i tylko bardzo mała pętla. Nie działa z liczbami ujemnymi, ale obsługuje wszystkie dodatnie
long
doLong.MAX_VALUE
:Wyjścia:
Wykonałem też naprawdę proste testy porównawcze (formatowanie 10 milionów losowych długości) i jest to znacznie szybsze niż implementacja Elijaha i nieco szybsza niż implementacja asylias.
źródło
Dla każdego, kto chce zaokrąglić. To świetne, łatwe do odczytania rozwiązanie, które korzysta z biblioteki Java.Lang.Math
źródło
Poniższy kod pokazuje, jak możesz to zrobić, mając na uwadze łatwe rozszerzenie.
„Magia” tkwi głównie w
makeDecimal
funkcji, która przy prawidłowych przekazanych wartościach gwarantuje, że na wyjściu nie będzie więcej niż cztery znaki.Najpierw wyodrębnia całość i części dziesiąte dla danego dzielnika, więc na przykład
12,345,678
z dzielnikiem1,000,000
dawhole
wartość12
itenths
wartość3
.Na tej podstawie może zdecydować, czy wyprowadza tylko całą część, czy zarówno całość, jak i części dziesiąte, stosując zasady:
Kod do tego jest następujący:
Następnie wystarczy wywołać tę funkcję pomocniczą z poprawnymi wartościami, w tym pewnymi stałymi, aby ułatwić życie programistom:
Fakt, że
makeDecimal
funkcja wykonuje podstawową pracę, oznacza, że rozszerzenie poza999,999,999
to tylko kwestia dodania dodatkowej liniiXlat
, tak łatwej, że zrobiłem to za Ciebie.Ostateczna
return
wXlat
nie potrzebuje warunkowa ponieważ największa wartość można trzymać w wersji 64-bitowej długości wynosi tylko około 9,2 trylionów.Ale jeśli z jakiegoś dziwacznego wymagania Oracle zdecyduje się dodać 128-bitowy
longer
lub 1024-bitowydamn_long
typ, będziesz na to gotowy :-)I na koniec mała wiązka testowa, której możesz użyć do sprawdzenia funkcjonalności.
Na podstawie wyników widać, że zapewnia to, czego potrzebujesz:
źródło
Nie wiem, czy to najlepsze podejście, ale tak właśnie zrobiłem.
--- Kod---
źródło
Moja funkcja do konwersji dużej liczby na małą (z 2 cyframi). Można zmienić liczbę cyfr, przez zmiany
#.##
wDecimalFormat
Testowanie
Mam nadzieję, że to pomoże
źródło
Moja Java jest zardzewiała, ale oto jak zaimplementuję ją w C #:
Łatwo byłoby to zmienić, aby użyć kilogramów CS (1024) zamiast kilogramów metrycznych lub dodać więcej jednostek. Formatuje 1000 jako „1,0 k” zamiast „1 k”, ale uważam, że to nieistotne.
Aby spełnić bardziej szczegółowy wymóg „nie więcej niż cztery znaki”, usuń spacje przed przyrostkami i dostosuj środkowy blok w następujący sposób:
źródło
ToString
metoda nie istnieje w Javie - będziesz potrzebować NumberFormat, który może powodować inne problemy (wrażliwe na ustawienia regionalne itp.).Mój ulubiony. Możesz użyć „k” i tak dalej jako wskaźnika dla liczb dziesiętnych, co jest powszechne w domenie elektronicznej. To da ci dodatkową cyfrę bez dodatkowego miejsca
Druga kolumna próbuje użyć jak największej liczby cyfr
To jest kod
źródło
Pozostając wiernym mojemu komentarzowi, że ceniłbym czytelność ponad wydajność, oto wersja, w której powinno być jasne, co się dzieje (zakładając, że użyłeś
BigDecimal
używałeś wcześniej) bez nadmiernego komentowania (wierzę w samodokumentujący się kod), bez martwienia się o wydajność (ponieważ nie mogę sobie wyobrazić scenariusza, w którym chciałbyś to zrobić tyle milionów razy, że wydajność nawet staje się brana pod uwagę).Ta wersja:
BigDecimal
s do precyzji i uniknięcia problemów z zaokrąglaniemHALF_UP
jak w testachREQUIRED_PRECISION
)enum
do określenia progów, tj. można go łatwo dostosować tak, aby używał KB / MB / GB / TB zamiast k / m / b / t itp., i oczywiście można go rozszerzyć pozaTRILLION
jeśli jest to wymaganeThreshold.java :
NumberShortener.java :
(Odkomentuj
println
instrukcje lub zmień, aby użyć ulubionego rejestratora, aby zobaczyć, co robi.)I wreszcie testy w NumberShortenerTest (zwykły JUnit 4):
Zapraszam do wskazania w komentarzach, czy przegapiłem istotny przypadek testowy lub czy oczekiwane wartości powinny zostać skorygowane.
źródło
TreeMap
podejście. „Czytelność” jest oczywiście subiektywna. ;-) A co, jeśli ktoś chce zaokrąglić inaczej niż obcinać w twojej wersji? (Na przykład, jeśli używasz tego do wskazania rozmiaru pliku, kto chciałby obciąć?) Jeśli chcesz potęgi 2 zamiast 10? Musiałbyś trochę przepisać, prawda? Jak powiedziałem, celowo nie próbowałem zagrać w golfa w swoim kodzie, z którego wiele można było skrócić (na przykład nigdy nie trzymałbym jeśli-to w jednej linii).to jest mój kod. czyste i proste.
źródło
Dodanie własnej odpowiedzi, kodu Java, kodu zrozumiałego ...
źródło
Ten fragment kodu jest po prostu śmiertelnie prosty i czysty, i całkowicie działa:
źródło
Spróbuj tego :
źródło
Wynik:
źródło
źródło