Я хотел бы отформатировать следующие числа в числа рядом с ними с помощью 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
Число справа будет длинным или целым числом, число слева будет строкой. Как я должен подойти к этому. Я уже разработал небольшой алгоритм для этого, но я подумал, что может быть уже что-то придумано, что делает его лучше и не требует дополнительного тестирования, если я начинаю работать с миллиардами и триллионами :)
Дополнительные требования:
- Формат должен содержать не более 4 символов
- Вышеуказанное означает, что 1.1k в порядке, 11.2k - нет. То же самое для 7,8 м в порядке, 19,1 м нет. Только одна цифра перед десятичной точкой может иметь десятичную точку. Две цифры перед десятичной точкой означают не цифры после десятичной точки.
- Нет округления не требуется. (Числа, отображаемые с добавленными символами k и m, являются скорее аналоговыми индикаторами, указывающими на приближение, а не на точную статью логики. Следовательно, округление не имеет значения, главным образом из-за природы переменной, которое может увеличивать или уменьшать несколько цифр, даже если вы смотрите на результат в кэше.)
java
number-formatting
Мат Б.
источник
источник
No rounding is necessary
этим, мне кажется абсурдной. Это просто усложнить вещи? Не лучше ли перефразировать этоRounding is not necessary, but welcome
?Ответы:
Вот решение, которое работает для любого длинного значения и которое я нахожу вполне читабельным (основная логика сделана в трех нижних строках
format
метода).Это
TreeMap
позволяет найти соответствующий суффикс. Это на удивление более эффективно, чем предыдущее решение, которое я написал, которое использовало массивы и было более трудным для чтения.Тестовый код
источник
-5821
должен быть отформатирован как-5k
, а не как-5.8k
.-
чтобы сохранить то же количество значащих цифр. Есть и другие варианты ...Я знаю, это больше похоже на программу на С, но она очень легкая!
Это выводит:
источник
Вот решение, которое использует инженерную нотацию DecimalFormat:
Вывод:
источник
Нужно некоторое улучшение, но: StrictMath на помощь!
Вы можете поместить суффикс в строку или массив и вызывать их в зависимости от мощности или чего-то подобного.
Разделением также можно управлять вокруг власти, я думаю, что почти все о силовой ценности. Надеюсь, поможет!
выходы:
источник
Проблемы с текущими ответами
Решение Java
Это решение (расширение этого ответа ) решает вышеуказанные проблемы.
Groovy Solution
Решение изначально было написано на Groovy, как показано ниже.
Тесты (Groovy)
Тесты написаны на Groovy, но их можно использовать для проверки либо Java, либо класса Groovy (поскольку они оба имеют одинаковое имя и API).
источник
Библиотека ICU имеет основанный на правилах форматер для чисел, который можно использовать для записи чисел и т. Д. Я думаю, что использование ICU даст вам удобочитаемое и удобное решение.
[Использование]
Правильный класс - RuleBasedNumberFormat. Сам формат может быть сохранен как отдельный файл (или как строковая константа, IIRC).
Пример из http://userguide.icu-project.org/formatparse/numbers
На этой же странице показаны римские цифры, так что, я думаю, ваш случай тоже возможен.
источник
CompactDecimalFormat
. Уровень API 24+С Java-12 + вы можете использовать
NumberFormat.getCompactNumberInstance
для форматирования чисел. Вы можете создатьNumberFormat
первый кака затем использовать его для
format
:источник
Важное замечание: Приведение ответов к
double
не удастся для чисел, подобных99999999999999999L
и возвращаемых,100P
а не99P
потому, чтоdouble
используетсяIEEE
стандарт :Это решение отсекает ненужные цифры и работает для всех
long
значений . Простая, но эффективная реализация (сравнение ниже). -120k не может быть выражено 4 символами, даже -0.1M слишком длинно, поэтому для отрицательных чисел 5 символов должны быть в порядке:Тест в
else if
начале необходим, потому что минимальное значение --(2^63)
максимальное,(2^63)-1
а максимальное - и, следовательно, назначениеnumber = -number
не выполнитсяnumber == Long.MIN_VALUE
. Если нам нужно сделать проверку, то мы можем включить как можно больше номеров вместо того, чтобы просто проверятьnumber == Long.MIN_VALUE
.Сравнение этой реализации с тем, кто получил наибольшее количество голосов (считается самым быстрым в настоящее время), показало, что она более чем в 5 раз быстрее (это зависит от настроек теста, но при большем количестве выигрыш становится больше, и эта реализация имеет делать больше проверок, потому что он обрабатывает все случаи, так что, если другой будет исправлен, разница станет еще больше). Это происходит так быстро, потому что нет операций с плавающей запятой, логарифма, мощности, рекурсии, регулярных выражений, сложных средств форматирования и минимизации количества создаваемых объектов.
Вот тестовая программа:
Возможный вывод:
2309 vs. 11591
(примерно то же самое, когда используются только положительные числа, и гораздо более экстремальный при изменении порядка выполнения, возможно, это как-то связано со сборкой мусора)источник
Вот короткая реализация без рекурсии и просто очень маленький цикл. Не работает с отрицательными числами, но поддерживает все положительные значения
long
вплоть доLong.MAX_VALUE
:Выходы:
Я также сделал несколько очень простых тестов (форматирование 10 миллионов случайных длин), и это значительно быстрее, чем реализация Илии, и немного быстрее, чем реализация ассилий.
источник
Для тех, кто хочет округлить. Это отличное, простое для чтения решение, использующее преимущества библиотеки Java.Lang.Math.
источник
Следующий код показывает, как вы можете сделать это, имея в виду простое расширение.
«Магия» заключается в основном в
makeDecimal
функции, которая при правильных передаваемых значениях гарантирует, что в выводе никогда не будет больше четырех символов.Сначала он извлекает целые и десятые доли для данного делителя, так что, например,
12,345,678
с делителем1,000,000
дастwhole
значение12
иtenths
значение3
.Исходя из этого, он может решить, будет ли он выводить только всю часть или как целую, так и десятую часть, используя правила:
Код для этого:
Затем достаточно просто вызвать вспомогательную функцию с правильными значениями, включая некоторые константы, чтобы облегчить жизнь разработчику:
Тот факт, что
makeDecimal
функция выполняет грубую работу, означает, что расширение за пределы999,999,999
просто вопрос добавления дополнительной строкиXlat
, настолько простой, что я сделал это для вас.Финал
return
вXlat
не нуждается в условном выражении, поскольку наибольшее значение, которое вы можете хранить в 64-битной длинной со знаком, составляет всего около 9,2 квинтиллионов.Но если по каким-то странным требованиям Oracle решит добавить 128-битный
longer
тип или 1024-битныйdamn_long
тип, вы будете к этому готовы :-)И, наконец, небольшой тестовый комплект, который вы можете использовать для проверки функциональности.
Из вывода видно, что он дает вам то, что вам нужно:
источник
Я не знаю, лучший ли это подход, но это то, что я сделал.
--- код ---
источник
Моя функция для преобразования большого числа в маленькое число (с 2 цифрами). Вы можете изменить количество цифр путем изменения
#.##
вDecimalFormat
тестирование
Надеюсь, это поможет
источник
Мой Java ржавый, но вот как я реализовал его в C #:
Было бы легко настроить это, чтобы использовать килограммы CS (1024), а не метрические, или добавить больше единиц. Он форматирует 1000 как «1.0 k», а не «1 k», но я уверен, что это несущественно.
Чтобы удовлетворить более конкретное требование «не более четырех символов», удалите пробелы перед суффиксами и отрегулируйте средний блок следующим образом:
источник
ToString
метод не существует в Java - вам понадобится NumberFormat, который может создавать другие проблемы (чувствительные к локали и т. Д.).Моя любимая. Вы можете использовать «k» и т. Д. В качестве индикатора для десятичной дроби, как это часто бывает в электронном домене. Это даст вам дополнительную цифру без дополнительного пробела
Второй столбец пытается использовать как можно больше цифр
Это код
источник
Оставаясь верным моему комментарию о том, что я ценю удобочитаемость выше производительности, вот версия, в которой должно быть ясно, что происходит (при условии, что вы использовали
BigDecimal
s ранее) без чрезмерного комментирования (я верю в самодокументируемый код), не беспокоясь о производительности. (поскольку я не могу представить сценарий, в котором вы бы хотели сделать это так много миллионов раз, что производительность даже станет фактором).Эта версия:
BigDecimal
s для точности и чтобы избежать проблем округленияHALF_UP
как в тестахREQUIRED_PRECISION
)enum
для определения пороговых значений, то есть может быть легко откорректирован для использования КБ / МБ / ГБ / ТБ вместо k / m / b / t и т. д. и, конечно, может быть расширен за пределыTRILLION
если требуетсяThreshold.java :
NumberShortener.java :
(Раскомментируйте
println
утверждения или измените, чтобы использовать свой любимый регистратор, чтобы увидеть, что он делает.)И, наконец, тесты в NumberShortenerTest (обычный JUnit 4):
Не стесняйтесь указывать в комментариях, если я пропустил значительный контрольный пример или ожидаемые значения должны быть скорректированы.
источник
TreeMap
подход. «Читабельность», конечно, субъективна. ;-) А что если кто-то захочет округлить иначе, чем усечь в вашей версии? (Например, когда вы используете это, чтобы указать размер файла, кто бы хотел усечь?) Если вам нужны степени 2, а не 10? Тебе придется переписать немало, не так ли? Как я уже сказал, я сознательно не пытался «сыграть в гольф» свой код, большую часть которого можно было бы сократить (например, я никогда не держал бы строку «если-тогда»).это мой код чисто и просто.
источник
Добавление моего собственного ответа, Java-код, понятный код ..
источник
Этот фрагмент кода просто смертельно простой, чистый код и полностью работает:
источник
попробуй это :
источник
Вывод:
источник
источник