Я пытался искать, но у меня возникла проблема с поиском полного решения этой проблемы:
Я хочу отформатировать Int
так, чтобы общее количество цифр всегда было 3. Несколько примеров:
1000000 -> 1,00m
678945 -> 678k
65432 -> 65,4k
5437 -> 5,43k
числа никогда не должны быть меньше 1000 или больше 1 миллиарда, поэтому другие случаи не имеют большого значения
это самое близкое, к чему я пришел:
@JvmStatic
fun formatPointsTop3(points: Int?): String {
if (points == null) return ""
val formatter = NumberFormat.getInstance(Locale.ITALIAN)
val mathContext = MathContext(3, RoundingMode.DOWN)
return when {
points < 1000 -> {
"$points"
}
points < 1000000 -> {
val bigDecimal = BigDecimal(points / 1000.0, mathContext)
"${formatter.format(bigDecimal)}k"
}
else -> {
val bigDecimal = BigDecimal(points / 1000000.0, mathContext)
"${formatter.format(bigDecimal)}m"
}
}
}
это работает нормально для большинства случаев, за исключением 1000000, которое выводит 1 м (я хочу 1,00 м). Добавление formatter.minimumFractionDigits = 2
добавляет десятичные дроби ко всем числам.
Есть ли способ добиться этого, не делая странных вещей непосредственно на строке?
Там должен быть. Во-первых, выясните, как вы хотите его отобразить, что, похоже, у вас есть разные взгляды на то, как именно на log (n) (например, на количество цифр во входных данных). Для 7 цифр вы хотите отобразить значение, разделенное на миллион, с 2 дробными цифрами. Для 8 цифр вам нужно значение div миллион с 1 дробью и т. д. Это будет много кода, возможно, манипуляции со строками проще.
В итоге я сделал это:
fun formatPointsTop3(points: Int?): String {
if (points == null) return ""
if (points == 0) return "0"
val maxNumberOfDigits = 3
val multiplierExponent = log(points.toDouble(), 1000.0).toInt()
val bigPoints = BigDecimal(points)
val bigDivider = BigDecimal(1000).pow(multiplierExponent)
val reducedPoints = bigPoints.divide(bigDivider)
val intPart = reducedPoints.toBigInteger().toInt()
val decimalPart = reducedPoints.subtract(BigDecimal(intPart)).toDouble()
val numberOfDecimals = maxNumberOfDigits - (log10(intPart.toDouble()).toInt() + 1)
var formattedString = "$intPart"
if (numberOfDecimals > 0) {
val multiplier = 10.0.pow(numberOfDecimals)
val formatter = NumberFormat.getIntegerInstance()
formatter.minimumIntegerDigits = numberOfDecimals
formatter.maximumIntegerDigits = numberOfDecimals
val multiplied = (decimalPart * multiplier).toInt()
formattedString += ",${formatter.format(multiplied)}"
}
formattedString += when (multiplierExponent) {
0 -> ""
1 -> "k"
2 -> "m"
3 -> "b"
else -> "" //this is not possible as max int is 2 billions
}
return formattedString
}
это довольно уродливо, но выглядит лучше, чем манипуляции со строками.