Je voudrais formater les nombres suivants dans les nombres à côté d'eux avec 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
Le nombre à droite sera long ou entier, le nombre à gauche sera une chaîne. Comment devrais-je aborder cela. J'ai déjà fait un petit algorithme pour cela, mais je pensais qu'il y avait peut-être déjà quelque chose d'inventé qui fasse un meilleur travail et ne nécessite pas de tests supplémentaires si je commence à traiter des milliards et des billions :)
Exigences supplémentaires:
- Le format doit comporter au maximum 4 caractères
- Ce qui précède signifie que 1,1k est OK 11,2k n'est pas. Même chose pour 7,8 m, c'est OK 19,1 m ne l'est pas. Un seul chiffre avant la virgule décimale peut avoir une virgule décimale. Deux chiffres avant la virgule décimale signifie pas de chiffres après la virgule décimale.
- Aucun arrondi n'est nécessaire. (Les nombres affichés avec k et m ajoutés sont davantage une jauge analogique indiquant une approximation et non un article de logique précis. Par conséquent, l'arrondi n'est pas pertinent, principalement en raison de la nature de la variable, car il peut augmenter ou décréter plusieurs chiffres même lorsque vous regardez le résultat mis en cache.)
java
number-formatting
Mat B.
la source
la source
No rounding is necessary
cela me semble absurde. Est-ce juste pour compliquer les choses? Ne serait-il pas préférable de reformuler cela enRounding is not necessary, but welcome
?Réponses:
Voici une solution qui fonctionne pour n'importe quelle valeur longue et que je trouve assez lisible (la logique de base se fait dans les trois dernières lignes du
format
méthode).Il utilise
TreeMap
pour trouver le suffixe approprié. Il est étonnamment plus efficace qu'une solution précédente que j'ai écrite qui utilisait des tableaux et était plus difficile à lire.Code de test
la source
-5821
doit être formaté comme-5k
, pas comme-5.8k
.-
pour conserver le même nombre de chiffres significatifs. Il y a d'autres options ...Je sais, cela ressemble plus à un programme C, mais c'est super léger!
Il sort:
la source
Voici une solution qui utilise la notation d'ingénierie de DecimalFormat:
Production:
la source
Besoin d'améliorations, mais: StrictMath à la rescousse!
Vous pouvez mettre le suffixe dans une chaîne ou un tableau et les récupérer en fonction de la puissance, ou quelque chose comme ça.
La division peut également être gérée autour de la puissance, je pense que presque tout est lié à la valeur de la puissance. J'espère que ça aide!
les sorties:
la source
Problèmes avec les réponses actuelles
Solution Java
Cette solution (une extension de cette réponse ) résout les problèmes ci-dessus.
Solution Groovy
La solution a été initialement écrite en Groovy comme indiqué ci-dessous.
Tests (Groovy)
Les tests sont écrits en Groovy mais peuvent être utilisés pour vérifier la classe Java ou Groovy (car ils ont tous les deux le même nom et l'API).
la source
La bibliothèque ICU a un formateur basé sur des règles pour les nombres, qui peut être utilisé pour l'orthographe des nombres, etc. Je pense que l'utilisation d'ICU vous donnerait une solution lisible et maintenable.
[Usage]
La bonne classe est RuleBasedNumberFormat. Le format lui-même peut être stocké en tant que fichier séparé (ou en tant que constante String, IIRC).
Exemple tiré de http://userguide.icu-project.org/formatparse/numbers
La même page montre des chiffres romains, donc je suppose que votre cas devrait également être possible.
la source
CompactDecimalFormat
. API Niveau 24+Avec Java-12 + , vous pouvez utiliser
NumberFormat.getCompactNumberInstance
pour formater les nombres. Vous pouvez créer uneNumberFormat
première commepuis utilisez-le pour
format
:la source
Important: les réponses envoyées à
double
échoueront pour les nombres comme99999999999999999L
et retourneront100P
au lieu de99P
parce quedouble
utilise laIEEE
norme :Cette solution supprime les chiffres indésirables et fonctionne pour tous
long
valeurs . Implémentation simple mais performante (comparaison ci-dessous). -120k ne peut pas être exprimé avec 4 caractères, même -0,1M est trop long, c'est pourquoi pour les nombres négatifs, 5 caractères doivent être corrects:Le test
else if
au début est nécessaire car le min est-(2^63)
et le max est(2^63)-1
et donc l'affectationnumber = -number
échouerait sinumber == Long.MIN_VALUE
. Si nous devons faire une vérification, nous pouvons également inclure autant de numéros que possible au lieu de simplement vérifiernumber == Long.MIN_VALUE
.La comparaison de cette implémentation avec celle qui a obtenu le plus de votes positifs (considérée comme la plus rapide actuellement) a montré qu'elle est plus de 5 fois plus rapide (cela dépend des paramètres de test, mais avec plus de nombres, le gain devient plus important et cette implémentation a faire plus de vérifications car il gère tous les cas, donc si l'autre était corrigé, la différence deviendrait encore plus grande). C'est aussi rapide car il n'y a pas d'opérations en virgule flottante, pas de logarithme, pas de puissance, pas de récursivité, pas de regex, pas de formateurs sophistiqués et une minimisation de la quantité d'objets créés.
Voici le programme de test:
Sortie possible:
2309 vs. 11591
(à peu près la même lorsque vous utilisez uniquement des nombres positifs et beaucoup plus extrême lors de l'inversion de l'ordre d'exécution, peut-être que cela a quelque chose à voir avec le ramasse-miettes)la source
Voici une courte implémentation sans récursivité et juste une très petite boucle. Ne fonctionne pas avec les nombres négatifs mais prend en charge tous les positifs
long
jusqu'àLong.MAX_VALUE
:Les sorties:
J'ai également fait un benchmarking très simple (formatage de 10 millions de longs aléatoires) et c'est considérablement plus rapide que l'implémentation d'Elijah et légèrement plus rapide que l'implémentation d'assylias.
la source
Pour tous ceux qui veulent arrondir. Il s'agit d'une excellente solution facile à lire, qui tire parti de la bibliothèque Java.Lang.Math
la source
Le code suivant montre comment vous pouvez le faire avec une expansion facile à l'esprit.
La "magie" réside principalement dans le
makeDecimal
fonction qui, pour les valeurs correctes transmises, garantit que vous n'aurez jamais plus de quatre caractères dans la sortie.Il extrait d'abord le tout et les dixièmes parties pour un diviseur donné ainsi, par exemple,
12,345,678
avec un diviseur de1,000,000
donnera unewhole
valeur de12
et unetenths
valeur de3
.À partir de là, il peut décider s'il sort uniquement la partie entière ou à la fois la partie entière et la dixième, en utilisant les règles:
Le code pour cela suit:
Ensuite, il suffit d'appeler cette fonction d'assistance avec les valeurs correctes, y compris certaines constantes pour faciliter la vie du développeur:
Le fait que la
makeDecimal
fonction fasse le gros travail signifie que s'étendre au999,999,999
- delà est juste une question d'ajouter une ligne supplémentaireXlat
, si facile que je l'ai fait pour vous.La finale
return
enXlat
n'a pas besoin conditionnel puisque la plus grande valeur que vous pouvez tenir dans un 64 bits signé longue est seulement d' environ 9,2 trillion.Mais si, par une exigence bizarre, Oracle décide d'ajouter un type 128 bits
longer
ou un type 1024 bitsdamn_long
, vous serez prêt pour cela :-)Et, enfin, un petit faisceau de test que vous pouvez utiliser pour valider la fonctionnalité.
Vous pouvez voir à partir de la sortie qu'il vous donne ce dont vous avez besoin:
la source
Je ne sais pas si c'est la meilleure approche, mais c'est ce que j'ai fait.
--- Code ---
la source
Ma fonction pour convertir un grand nombre en petit nombre (avec 2 chiffres). Vous pouvez modifier le nombre de chiffres par le changement
#.##
dansDecimalFormat
Essai
J'espère que ça aide
la source
Mon Java est rouillé, mais voici comment je l'implémenterais en C #:
Il serait facile d'ajuster cela pour utiliser des kilos CS (1 024) plutôt que des kilos métriques, ou pour ajouter plus d'unités. Il formate 1 000 en tant que «1,0 k» plutôt que «1 k», mais j'espère que c'est sans importance.
Pour répondre à l'exigence plus spécifique "pas plus de quatre caractères", supprimez les espaces avant les suffixes et ajustez le bloc du milieu comme ceci:
la source
ToString
méthode n'existe pas en Java - vous auriez besoin d'un NumberFormat qui peut créer d'autres problèmes (sensibles aux paramètres régionaux, etc.).Mon préféré. Vous pouvez également utiliser "k" et ainsi de suite comme indicateur de décimal, comme cela est courant dans le domaine électronique. Cela vous donnera un chiffre supplémentaire sans espace supplémentaire
La deuxième colonne essaie d'utiliser autant de chiffres que possible
C'est le code
la source
En restant fidèle à mon commentaire selon lequel j'apprécierais la lisibilité au-dessus des performances, voici une version où il devrait être clair ce qui se passe (en supposant que vous ayez utilisé
BigDecimal
s) sans commentaires excessifs (je crois au code auto-documenté), sans vous soucier des performances (puisque je ne peux pas imaginer un scénario où vous voudriez faire cela tant de millions de fois que la performance devient même une considération).Cette version:
BigDecimal
s pour la précision et pour éviter les problèmes d'arrondiHALF_UP
comme dans les testsREQUIRED_PRECISION
)enum
pour définir les seuils, c'est-à-dire pourrait être facilement ajusté pour utiliser KB / MB / GB / TB au lieu de k / m / b / t, etc., et pourrait bien sûr être étendu auTRILLION
- delà si nécessaireThreshold.java :
NumberShortener.java :
(Décommentez les
println
déclarations ou changez pour utiliser votre enregistreur préféré pour voir ce qu'il fait.)Et enfin, les tests dans NumberShortenerTest (plain JUnit 4):
N'hésitez pas à préciser dans les commentaires si j'ai manqué un cas de test significatif ou si les valeurs attendues doivent être ajustées.
la source
TreeMap
approche. La «lisibilité» est bien entendu subjective. ;-) Et si quelqu'un veut arrondir différemment de la troncature dans votre version? (Par exemple, lorsque vous l'utilisez pour indiquer la taille du fichier, qui voudrait tronquer?) Si vous voulez des puissances de 2 plutôt que 10? Vous auriez à réécrire un peu, n'est-ce pas? Comme je l'ai dit, je n'essayais délibérément pas de jouer au golf sur mon code, dont une grande partie aurait pu être raccourcie (je ne garderais jamais un si-alors sur une seule ligne, par exemple).c'est mon code. propre et simple.
la source
Ajout de ma propre réponse, du code Java, du code explicite.
la source
Cet extrait de code est juste un code mortellement simple et propre, et fonctionne totalement:
la source
essaye ça :
la source
Production:
la source
la source